onlinescoutmanager 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,368 @@
1
+ interface ClientOptions {
2
+ apiId: string;
3
+ token: string;
4
+ baseUrl?: string;
5
+ }
6
+ interface AuthCredentials {
7
+ userid: string;
8
+ secret: string;
9
+ }
10
+ interface AuthResponse {
11
+ userid: string;
12
+ secret: string;
13
+ }
14
+ interface MemberListItem {
15
+ scoutid: number;
16
+ firstname: string;
17
+ lastname: string;
18
+ full_name: string;
19
+ photo_guid: string;
20
+ patrolid: number;
21
+ patrol: string;
22
+ sectionid: number;
23
+ enddate: string | null;
24
+ age: string;
25
+ patrol_role_level_label: string;
26
+ active: boolean;
27
+ }
28
+ interface MembersList {
29
+ identifier: string;
30
+ photos: boolean;
31
+ items: MemberListItem[];
32
+ }
33
+ interface MemberDetail {
34
+ ok: boolean;
35
+ read_only: string[];
36
+ data: Record<string, unknown>;
37
+ meta: Record<string, unknown>[];
38
+ }
39
+ interface MemberTransfer {
40
+ direction: string;
41
+ member_id: number;
42
+ firstname: string;
43
+ lastname: string;
44
+ photo_guid: string;
45
+ type: string;
46
+ date: string;
47
+ section_id: number;
48
+ section_name: {
49
+ group: string;
50
+ section: string;
51
+ };
52
+ section_long: string;
53
+ mode: string;
54
+ id: string;
55
+ }
56
+ interface MemberTransfersResponse {
57
+ status: boolean;
58
+ error: string | null;
59
+ data: MemberTransfer[];
60
+ meta: unknown[];
61
+ }
62
+ interface PatrolMember {
63
+ firstname: string;
64
+ lastname: string;
65
+ scout_id: number;
66
+ scoutid: number;
67
+ photo_guid: string;
68
+ patrolid: number;
69
+ patrolleader: string;
70
+ patrol: string;
71
+ sectionid: number;
72
+ enddate: string | null;
73
+ age: string;
74
+ patrol_role_level_label: string;
75
+ active: number;
76
+ editable: boolean;
77
+ }
78
+ interface Patrol {
79
+ patrolid: string;
80
+ sectionid: string;
81
+ name: string;
82
+ active: string;
83
+ points: string;
84
+ census_costs: boolean;
85
+ members: PatrolMember[];
86
+ }
87
+ type PatrolsResponse = Record<string, Patrol>;
88
+ interface CensusItem {
89
+ scoutid: string;
90
+ firstname: string;
91
+ lastname: string;
92
+ joined: string;
93
+ photo_guid: string | null;
94
+ sex: string;
95
+ ethnicity: string;
96
+ disabilities: string;
97
+ myscout: string;
98
+ raw_disabilities: string[];
99
+ _filterString: string;
100
+ }
101
+ interface CensusResponse {
102
+ identifier: string;
103
+ items: CensusItem[];
104
+ }
105
+ interface FlexiRecordItem {
106
+ extraid: string;
107
+ name: string;
108
+ }
109
+ interface FlexiRecordsResponse {
110
+ identifier: string;
111
+ label: string;
112
+ items: FlexiRecordItem[];
113
+ }
114
+ interface AttendanceItem {
115
+ firstname: string;
116
+ lastname: string;
117
+ patrolid: number;
118
+ active: boolean;
119
+ scoutid: number;
120
+ total: number;
121
+ [date: string]: unknown;
122
+ }
123
+ interface AttendanceResponse {
124
+ identifier: string;
125
+ label: string;
126
+ items: AttendanceItem[];
127
+ meetings: Record<string, string>;
128
+ }
129
+ interface AttendanceBadgeRequirement {
130
+ badge_id: string;
131
+ badgeName: string;
132
+ column_id: string;
133
+ name: string;
134
+ meetingdate: string;
135
+ section: string;
136
+ sectionid: number;
137
+ }
138
+ interface UpdateAttendanceParams {
139
+ sectionId: string;
140
+ termId: string;
141
+ scoutIds: number[];
142
+ selectedDate: string;
143
+ present: string;
144
+ section: string;
145
+ completedBadges?: unknown[];
146
+ customData?: unknown[];
147
+ }
148
+ interface ProgrammeSummaryItem {
149
+ eveningid: string;
150
+ sectionid: string;
151
+ title: string;
152
+ notesforparents: string;
153
+ parentsrequired: string;
154
+ meetingdate: string;
155
+ starttime: string;
156
+ endtime: string;
157
+ soft_deleted: string;
158
+ }
159
+ interface ProgrammeSummaryResponse {
160
+ items: ProgrammeSummaryItem[];
161
+ }
162
+ interface ProgrammeDetailItem {
163
+ eveningid: string;
164
+ sectionid: string;
165
+ title: string;
166
+ meetingdate: string;
167
+ starttime: string;
168
+ endtime: string;
169
+ help: {
170
+ scoutid: string;
171
+ scout: string;
172
+ }[];
173
+ }
174
+ interface ProgrammeDetailsResponse {
175
+ items: ProgrammeDetailItem[];
176
+ badgelinks: Record<string, unknown>;
177
+ }
178
+ interface ParentRotaMember {
179
+ scoutid: string;
180
+ firstname: string;
181
+ lastname: string;
182
+ photo_guid: string;
183
+ patrol_id: number;
184
+ }
185
+ interface ParentRotaResponse {
186
+ status: boolean;
187
+ error: string | null;
188
+ data: ParentRotaMember[];
189
+ meta: unknown[];
190
+ }
191
+ interface BadgeTagCloudResponse {
192
+ tags: Record<string, number>;
193
+ tag_count: number;
194
+ badges: Record<string, number>;
195
+ }
196
+ interface DashboardResponse {
197
+ conf: Record<string, number>;
198
+ is_full_admin: boolean;
199
+ permissions: Record<string, unknown>;
200
+ patrols: Record<string, unknown>[];
201
+ birthdays: Record<string, unknown>[];
202
+ programme: Record<string, unknown>[];
203
+ events: Record<string, unknown>[];
204
+ outstandingpayments: Record<string, unknown>[];
205
+ notepad: {
206
+ raw: string;
207
+ html: string;
208
+ };
209
+ [key: string]: unknown;
210
+ }
211
+ interface CustomDataColumn {
212
+ column_id: number;
213
+ type: string;
214
+ varname: string;
215
+ label: string;
216
+ value: string | null;
217
+ }
218
+ interface CustomDataGroup {
219
+ group_id: number;
220
+ group_type: string;
221
+ identifier: string;
222
+ name: string;
223
+ columns: CustomDataColumn[];
224
+ }
225
+ interface CustomDataResponse {
226
+ status: boolean;
227
+ error: string | null;
228
+ data: CustomDataGroup[];
229
+ meta: Record<string, unknown>;
230
+ }
231
+ interface CustomDataUpdateResponse {
232
+ status: boolean;
233
+ error: string | null;
234
+ data: Record<string, unknown>;
235
+ meta: Record<string, unknown>;
236
+ }
237
+ interface EmailContact {
238
+ emails: string[];
239
+ firstname: string;
240
+ lastname: string;
241
+ photo_guid: string;
242
+ member_id: number;
243
+ }
244
+ interface SelectedEmailsResponse {
245
+ emails: Record<string, EmailContact>;
246
+ count: number;
247
+ blocks: unknown[];
248
+ daily_limit_reached: boolean;
249
+ }
250
+ interface SectionsResponse {
251
+ [key: string]: unknown;
252
+ }
253
+ interface RiskAssessmentCategoriesResponse {
254
+ status: boolean;
255
+ error: string | null;
256
+ data: {
257
+ name: string;
258
+ }[];
259
+ meta: Record<string, unknown>;
260
+ }
261
+ interface DeletableMembersResponse {
262
+ status: boolean;
263
+ error: string | null;
264
+ data: {
265
+ firstname: string;
266
+ lastname: string;
267
+ date_deleted: string;
268
+ id: number;
269
+ }[];
270
+ meta: unknown[];
271
+ }
272
+ interface OkResponse {
273
+ ok: boolean;
274
+ }
275
+
276
+ declare class AttendanceResource {
277
+ private client;
278
+ constructor(client: OSMClient);
279
+ get(sectionId: string, termId: string, section: string): Promise<AttendanceResponse>;
280
+ getBadgeRequirements(sectionId: string, section: string, date: string): Promise<AttendanceBadgeRequirement[]>;
281
+ update(params: UpdateAttendanceParams): Promise<OkResponse>;
282
+ }
283
+
284
+ declare class BadgesResource {
285
+ private client;
286
+ constructor(client: OSMClient);
287
+ getTagCloud(sectionId: string, termId: string, section: string): Promise<BadgeTagCloudResponse>;
288
+ }
289
+
290
+ declare class CustomDataResource {
291
+ private client;
292
+ constructor(client: OSMClient);
293
+ get(sectionId: string, memberId: string): Promise<CustomDataResponse>;
294
+ update(sectionId: string, memberId: string, groupId: string, data: Record<string, string>): Promise<CustomDataUpdateResponse>;
295
+ }
296
+
297
+ declare class DashboardResource {
298
+ private client;
299
+ constructor(client: OSMClient);
300
+ getNextThings(sectionId: string, termId: string, section: string): Promise<DashboardResponse>;
301
+ }
302
+
303
+ declare class EmailResource {
304
+ private client;
305
+ constructor(client: OSMClient);
306
+ getContacts(sectionId: string): Promise<SelectedEmailsResponse>;
307
+ sendTemplate(sectionId: string, subject: string, emails: Record<string, unknown>, edits: Record<string, unknown>): Promise<OkResponse>;
308
+ }
309
+
310
+ declare class MembersResource {
311
+ private client;
312
+ constructor(client: OSMClient);
313
+ list(sectionId: string, termId: string): Promise<MembersList>;
314
+ get(sectionId: string, scoutId: string): Promise<MemberDetail>;
315
+ getTransfers(sectionId: string): Promise<MemberTransfersResponse>;
316
+ getPatrols(sectionId: string, termId: string): Promise<PatrolsResponse>;
317
+ getCensus(sectionId: string, termId: string): Promise<CensusResponse>;
318
+ getFlexiRecords(sectionId: string, archived?: boolean): Promise<FlexiRecordsResponse>;
319
+ getDeletable(sectionId: string): Promise<DeletableMembersResponse>;
320
+ }
321
+
322
+ declare class ProgrammeResource {
323
+ private client;
324
+ constructor(client: OSMClient);
325
+ getSummary(sectionId: string, termId: string): Promise<ProgrammeSummaryResponse>;
326
+ getDetails(sectionId: string, eveningId: string): Promise<ProgrammeDetailsResponse>;
327
+ getParentRotaMembers(sectionId: string, eveningId: string): Promise<ParentRotaResponse>;
328
+ getAttachments(sectionId: string, eveningId: string): Promise<unknown>;
329
+ updateMeeting(sectionId: string, eveningId: string, parts: Record<string, unknown>): Promise<ProgrammeDetailsResponse>;
330
+ }
331
+
332
+ declare class SectionsResource {
333
+ private client;
334
+ constructor(client: OSMClient);
335
+ list(): Promise<SectionsResponse>;
336
+ getTerms(): Promise<unknown>;
337
+ }
338
+
339
+ declare class OSMClient {
340
+ readonly apiId: string;
341
+ readonly token: string;
342
+ readonly baseUrl: string;
343
+ private auth;
344
+ readonly members: MembersResource;
345
+ readonly attendance: AttendanceResource;
346
+ readonly programme: ProgrammeResource;
347
+ readonly sections: SectionsResource;
348
+ readonly badges: BadgesResource;
349
+ readonly dashboard: DashboardResource;
350
+ readonly customData: CustomDataResource;
351
+ readonly email: EmailResource;
352
+ constructor(options: ClientOptions);
353
+ get isAuthorized(): boolean;
354
+ authorize(email: string, password: string): Promise<void>;
355
+ post<T>(path: string, body?: Record<string, string>, skipAuth?: boolean): Promise<T>;
356
+ get<T>(path: string, query?: Record<string, string>): Promise<T>;
357
+ }
358
+
359
+ declare class OSMError extends Error {
360
+ readonly status: number;
361
+ readonly body: unknown;
362
+ constructor(message: string, status: number, body?: unknown);
363
+ }
364
+ declare class OSMAuthError extends OSMError {
365
+ constructor(message?: string);
366
+ }
367
+
368
+ export { type AttendanceBadgeRequirement, type AttendanceItem, type AttendanceResponse, type AuthCredentials, type AuthResponse, type BadgeTagCloudResponse, type CensusItem, type CensusResponse, type ClientOptions, type CustomDataColumn, type CustomDataGroup, type CustomDataResponse, type CustomDataUpdateResponse, type DashboardResponse, type DeletableMembersResponse, type EmailContact, type FlexiRecordItem, type FlexiRecordsResponse, type MemberDetail, type MemberListItem, type MemberTransfer, type MemberTransfersResponse, type MembersList, OSMAuthError, OSMClient, OSMError, type OkResponse, type ParentRotaMember, type ParentRotaResponse, type Patrol, type PatrolMember, type PatrolsResponse, type ProgrammeDetailItem, type ProgrammeDetailsResponse, type ProgrammeSummaryItem, type ProgrammeSummaryResponse, type RiskAssessmentCategoriesResponse, type SectionsResponse, type SelectedEmailsResponse, type UpdateAttendanceParams };
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ // src/errors.ts
2
+ var OSMError = class extends Error {
3
+ status;
4
+ body;
5
+ constructor(message, status, body) {
6
+ super(message);
7
+ this.name = "OSMError";
8
+ this.status = status;
9
+ this.body = body;
10
+ }
11
+ };
12
+ var OSMAuthError = class extends OSMError {
13
+ constructor(message = "Not authorized \u2014 call client.authorize() first") {
14
+ super(message, 401);
15
+ this.name = "OSMAuthError";
16
+ }
17
+ };
18
+
19
+ // src/resources/attendance.ts
20
+ var AttendanceResource = class {
21
+ constructor(client) {
22
+ this.client = client;
23
+ }
24
+ async get(sectionId, termId, section) {
25
+ return this.client.post(
26
+ "/ext/members/attendance/?action=get",
27
+ { sectionid: sectionId, termid: termId, section }
28
+ );
29
+ }
30
+ async getBadgeRequirements(sectionId, section, date) {
31
+ return this.client.post(
32
+ "/ext/members/attendance/?action=getAttendanceBadgeRequirements",
33
+ { sectionid: sectionId, section, date }
34
+ );
35
+ }
36
+ async update(params) {
37
+ return this.client.post(
38
+ `/ext/members/attendance/?action=update&sectionid=${params.sectionId}&termid=${params.termId}`,
39
+ {
40
+ scouts: JSON.stringify(params.scoutIds),
41
+ selectedDate: params.selectedDate,
42
+ present: params.present,
43
+ section: params.section,
44
+ sectionid: params.sectionId,
45
+ completedBadges: JSON.stringify(params.completedBadges ?? []),
46
+ customData: JSON.stringify(params.customData ?? [])
47
+ }
48
+ );
49
+ }
50
+ };
51
+
52
+ // src/resources/badges.ts
53
+ var BadgesResource = class {
54
+ constructor(client) {
55
+ this.client = client;
56
+ }
57
+ async getTagCloud(sectionId, termId, section) {
58
+ return this.client.post(
59
+ "/ext/programme/clouds/?action=getBadgeTagCloud",
60
+ { sectionid: sectionId, termid: termId, section }
61
+ );
62
+ }
63
+ };
64
+
65
+ // src/resources/custom-data.ts
66
+ var CustomDataResource = class {
67
+ constructor(client) {
68
+ this.client = client;
69
+ }
70
+ async get(sectionId, memberId) {
71
+ return this.client.post(
72
+ "/ext/customdata/?action=getData",
73
+ {
74
+ section_id: sectionId,
75
+ associated_id: memberId,
76
+ associated_type: "member",
77
+ context: "members",
78
+ group_order: "section"
79
+ }
80
+ );
81
+ }
82
+ async update(sectionId, memberId, groupId, data) {
83
+ const body = {
84
+ section_id: sectionId,
85
+ associated_id: memberId,
86
+ associated_type: "member",
87
+ group_id: groupId,
88
+ context: "members"
89
+ };
90
+ for (const [key, value] of Object.entries(data)) {
91
+ body[`data[${key}]`] = value;
92
+ }
93
+ return this.client.post(
94
+ "/ext/customdata/?action=update",
95
+ body
96
+ );
97
+ }
98
+ };
99
+
100
+ // src/resources/dashboard.ts
101
+ var DashboardResource = class {
102
+ constructor(client) {
103
+ this.client = client;
104
+ }
105
+ async getNextThings(sectionId, termId, section) {
106
+ return this.client.post(
107
+ "/ext/dashboard/?action=getNextThings",
108
+ { sectionid: sectionId, termid: termId, section }
109
+ );
110
+ }
111
+ };
112
+
113
+ // src/resources/email.ts
114
+ var EmailResource = class {
115
+ constructor(client) {
116
+ this.client = client;
117
+ }
118
+ async getContacts(sectionId) {
119
+ return this.client.post(
120
+ "/ext/members/email/?action=getSelectedEmailsFromContacts",
121
+ { sectionid: sectionId }
122
+ );
123
+ }
124
+ async sendTemplate(sectionId, subject, emails, edits) {
125
+ return this.client.post(
126
+ "/ext/members/email/?action=sendTemplate",
127
+ {
128
+ sectionid: sectionId,
129
+ subject,
130
+ emails: JSON.stringify(emails),
131
+ edits: JSON.stringify(edits)
132
+ }
133
+ );
134
+ }
135
+ };
136
+
137
+ // src/resources/members.ts
138
+ var MembersResource = class {
139
+ constructor(client) {
140
+ this.client = client;
141
+ }
142
+ async list(sectionId, termId) {
143
+ return this.client.post(
144
+ "/ext/members/contact/?action=getListOfMembers",
145
+ { sectionid: sectionId, termid: termId }
146
+ );
147
+ }
148
+ async get(sectionId, scoutId) {
149
+ return this.client.post(
150
+ "/ext/members/contact/?action=getIndividual",
151
+ {
152
+ sectionid: sectionId,
153
+ scoutid: scoutId,
154
+ context: "members"
155
+ }
156
+ );
157
+ }
158
+ async getTransfers(sectionId) {
159
+ return this.client.post(
160
+ "/ext/members/contact/?action=getMemberTransfers",
161
+ { sectionid: sectionId }
162
+ );
163
+ }
164
+ async getPatrols(sectionId, termId) {
165
+ return this.client.post(
166
+ "/ext/members/patrols/?action=getPatrolsWithPeople",
167
+ { sectionid: sectionId, termid: termId }
168
+ );
169
+ }
170
+ async getCensus(sectionId, termId) {
171
+ return this.client.post(
172
+ "/ext/members/census/?action=getDetails",
173
+ { sectionid: sectionId, termid: termId }
174
+ );
175
+ }
176
+ async getFlexiRecords(sectionId, archived = false) {
177
+ return this.client.post(
178
+ "/ext/members/flexirecords/?action=getPatrolsWithPeople",
179
+ { sectionid: sectionId, archived: archived ? "y" : "n" }
180
+ );
181
+ }
182
+ async getDeletable(sectionId) {
183
+ return this.client.get(
184
+ `/v3/members/review/deletion/${sectionId}`
185
+ );
186
+ }
187
+ };
188
+
189
+ // src/resources/programme.ts
190
+ var ProgrammeResource = class {
191
+ constructor(client) {
192
+ this.client = client;
193
+ }
194
+ async getSummary(sectionId, termId) {
195
+ return this.client.post(
196
+ "/ext/programme/?action=getProgrammeSummary",
197
+ { sectionid: sectionId, termid: termId }
198
+ );
199
+ }
200
+ async getDetails(sectionId, eveningId) {
201
+ return this.client.post(
202
+ "/ext/programme/?action=getProgramme",
203
+ { sectionid: sectionId, eveningid: eveningId }
204
+ );
205
+ }
206
+ async getParentRotaMembers(sectionId, eveningId) {
207
+ return this.client.post(
208
+ "/ext/programme/?action=getMembersForParentRota",
209
+ { sectionid: sectionId, eveningid: eveningId }
210
+ );
211
+ }
212
+ async getAttachments(sectionId, eveningId) {
213
+ return this.client.post(
214
+ "/ext/programme/?action=programmeAttachmentsManifest",
215
+ { sectionid: sectionId, eveningid: eveningId }
216
+ );
217
+ }
218
+ async updateMeeting(sectionId, eveningId, parts) {
219
+ return this.client.post(
220
+ "/ext/programme/?action=editEveningParts",
221
+ {
222
+ sectionid: sectionId,
223
+ eveningid: eveningId,
224
+ parts: JSON.stringify(parts)
225
+ }
226
+ );
227
+ }
228
+ };
229
+
230
+ // src/resources/sections.ts
231
+ var SectionsResource = class {
232
+ constructor(client) {
233
+ this.client = client;
234
+ }
235
+ async list() {
236
+ return this.client.post(
237
+ "/ext/members/sectionplanning/?action=listSections"
238
+ );
239
+ }
240
+ async getTerms() {
241
+ return this.client.post("/api.php?action=getTerms");
242
+ }
243
+ };
244
+
245
+ // src/client.ts
246
+ var DEFAULT_BASE_URL = "https://www.onlinescoutmanager.co.uk";
247
+ var OSMClient = class {
248
+ apiId;
249
+ token;
250
+ baseUrl;
251
+ auth = null;
252
+ members;
253
+ attendance;
254
+ programme;
255
+ sections;
256
+ badges;
257
+ dashboard;
258
+ customData;
259
+ email;
260
+ constructor(options) {
261
+ this.apiId = options.apiId;
262
+ this.token = options.token;
263
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
264
+ this.members = new MembersResource(this);
265
+ this.attendance = new AttendanceResource(this);
266
+ this.programme = new ProgrammeResource(this);
267
+ this.sections = new SectionsResource(this);
268
+ this.badges = new BadgesResource(this);
269
+ this.dashboard = new DashboardResource(this);
270
+ this.customData = new CustomDataResource(this);
271
+ this.email = new EmailResource(this);
272
+ }
273
+ get isAuthorized() {
274
+ return this.auth !== null;
275
+ }
276
+ async authorize(email, password) {
277
+ const data = await this.post(
278
+ "/users.php?action=authorise",
279
+ { email, password },
280
+ true
281
+ );
282
+ this.auth = { userid: data.userid, secret: data.secret };
283
+ }
284
+ async post(path, body = {}, skipAuth = false) {
285
+ const params = new URLSearchParams({
286
+ apiid: this.apiId,
287
+ token: this.token,
288
+ ...body
289
+ });
290
+ if (!skipAuth) {
291
+ if (!this.auth) throw new OSMAuthError();
292
+ params.set("userid", this.auth.userid);
293
+ params.set("secret", this.auth.secret);
294
+ }
295
+ const url = `${this.baseUrl}${path}`;
296
+ const response = await fetch(url, {
297
+ method: "POST",
298
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
299
+ body: params.toString()
300
+ });
301
+ if (!response.ok) {
302
+ const text = await response.text().catch(() => "");
303
+ throw new OSMError(
304
+ `OSM API error: ${response.status} ${response.statusText}`,
305
+ response.status,
306
+ text
307
+ );
308
+ }
309
+ return response.json();
310
+ }
311
+ async get(path, query = {}) {
312
+ if (!this.auth) throw new OSMAuthError();
313
+ const params = new URLSearchParams(query);
314
+ const url = `${this.baseUrl}${path}?${params.toString()}`;
315
+ const response = await fetch(url, {
316
+ method: "GET",
317
+ headers: {
318
+ Authorization: `${this.auth.userid}:${this.auth.secret}`
319
+ }
320
+ });
321
+ if (!response.ok) {
322
+ const text = await response.text().catch(() => "");
323
+ throw new OSMError(
324
+ `OSM API error: ${response.status} ${response.statusText}`,
325
+ response.status,
326
+ text
327
+ );
328
+ }
329
+ return response.json();
330
+ }
331
+ };
332
+ export {
333
+ OSMAuthError,
334
+ OSMClient,
335
+ OSMError
336
+ };