@totoday/quinn-sdk 0.1.2 → 0.2.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/README.md CHANGED
@@ -34,6 +34,16 @@ const people = await quinn.members.batchGet({
34
34
  ids: ["user-id-1"],
35
35
  emails: ["user@example.com"],
36
36
  });
37
+ const created = await quinn.members.create({
38
+ email: "new.user@example.com",
39
+ firstName: "New",
40
+ lastName: "User",
41
+ sendInvite: false,
42
+ });
43
+ if (created) {
44
+ await quinn.members.updateRoles({ memberId: created.userId, roleIds: ["role-id"] });
45
+ await quinn.members.updateManager({ memberId: created.userId, managerUid: "manager-uid" });
46
+ }
37
47
 
38
48
  // role -> level -> competencies
39
49
  const roles = await quinn.roles.list();
@@ -60,6 +70,28 @@ Default `apiUrl` is `https://api.lunapark.com`.
60
70
 
61
71
  `token` and `orgId` are required.
62
72
 
73
+ ## Mutation Access
74
+
75
+ By default, the SDK preserves current behavior and uses `mutationAccess: "full_access"`.
76
+
77
+ You can explicitly restrict Quinn business mutations:
78
+
79
+ ```ts
80
+ import { Quinn } from "@totoday/quinn-sdk";
81
+
82
+ const quinn = new Quinn({
83
+ mutationAccess: "read_only",
84
+ });
85
+ ```
86
+
87
+ Supported values:
88
+
89
+ - `read_only`: blocks SDK mutation methods
90
+ - `needs_confirmation`: also blocks mutation methods for now, but throws a distinct confirmation-required error
91
+ - `full_access`: allows mutation methods
92
+
93
+ This setting does not affect local file writes or sandbox execution. It only gates Quinn business mutations through the SDK.
94
+
63
95
  For password login from scripts, use `QuinnAuth`:
64
96
 
65
97
  ```ts
package/dist/config.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { AxiosInstance } from 'axios';
2
+ import { QuinnMutationAccess } from './mutation-access';
2
3
  export declare const DEFAULT_QUINN_API_URL = "https://api.lunapark.com";
3
4
  export interface QuinnClientConfig {
4
5
  apiUrl?: string;
@@ -6,12 +7,14 @@ export interface QuinnClientConfig {
6
7
  orgId?: string;
7
8
  configPath?: string;
8
9
  httpClient?: AxiosInstance;
10
+ mutationAccess?: QuinnMutationAccess;
9
11
  }
10
12
  export interface QuinnResolvedConfig {
11
13
  apiUrl: string;
12
14
  token: string;
13
15
  orgId: string;
14
16
  httpClient?: AxiosInstance;
17
+ mutationAccess: QuinnMutationAccess;
15
18
  }
16
19
  export declare function resolveQuinnConfig(input: QuinnClientConfig): QuinnResolvedConfig;
17
20
  export declare function resolveApiUrl(input?: {
package/dist/config.js CHANGED
@@ -17,6 +17,7 @@ function resolveQuinnConfig(input) {
17
17
  const apiUrl = firstNonEmpty(input.apiUrl, process.env.QUINN_API_URL, fileConfig.apiUrl, exports.DEFAULT_QUINN_API_URL);
18
18
  const token = firstNonEmpty(input.token, process.env.QUINN_API_TOKEN, fileConfig.token);
19
19
  const orgId = firstNonEmpty(input.orgId, process.env.QUINN_ORG_ID, fileConfig.orgId);
20
+ const mutationAccess = resolveMutationAccess(input.mutationAccess, process.env.QUINN_MUTATION_ACCESS, fileConfig.mutationAccess);
20
21
  if (!apiUrl) {
21
22
  throw new Error('missing apiUrl');
22
23
  }
@@ -31,6 +32,7 @@ function resolveQuinnConfig(input) {
31
32
  token,
32
33
  orgId,
33
34
  httpClient: input.httpClient,
35
+ mutationAccess,
34
36
  };
35
37
  }
36
38
  function resolveApiUrl(input) {
@@ -55,12 +57,22 @@ function readConfigFile(configPath) {
55
57
  apiUrl: asNonEmptyString(parsed.apiUrl),
56
58
  token: asNonEmptyString(parsed.token),
57
59
  orgId: asNonEmptyString(parsed.orgId),
60
+ mutationAccess: asMutationAccess(parsed.mutationAccess),
58
61
  };
59
62
  }
60
63
  catch {
61
64
  return {};
62
65
  }
63
66
  }
67
+ function resolveMutationAccess(...values) {
68
+ for (const value of values) {
69
+ const parsed = asMutationAccess(value);
70
+ if (parsed) {
71
+ return parsed;
72
+ }
73
+ }
74
+ return 'full_access';
75
+ }
64
76
  function firstNonEmpty(...values) {
65
77
  for (const value of values) {
66
78
  const normalized = asNonEmptyString(value);
@@ -77,3 +89,9 @@ function asNonEmptyString(value) {
77
89
  const trimmed = value.trim();
78
90
  return trimmed === '' ? undefined : trimmed;
79
91
  }
92
+ function asMutationAccess(value) {
93
+ if (value !== 'read_only' && value !== 'needs_confirmation' && value !== 'full_access') {
94
+ return undefined;
95
+ }
96
+ return value;
97
+ }
package/dist/http.d.ts CHANGED
@@ -2,5 +2,6 @@ import { AxiosInstance } from 'axios';
2
2
  export interface QuinnHttpConfig {
3
3
  apiUrl: string;
4
4
  token: string;
5
+ orgId: string;
5
6
  }
6
7
  export declare function createQuinnHttpClient(config: QuinnHttpConfig): AxiosInstance;
package/dist/http.js CHANGED
@@ -7,7 +7,7 @@ exports.createQuinnHttpClient = createQuinnHttpClient;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  function createQuinnHttpClient(config) {
9
9
  return axios_1.default.create({
10
- baseURL: config.apiUrl,
10
+ baseURL: `${config.apiUrl}/platform/v1/orgs/${config.orgId}`,
11
11
  headers: {
12
12
  Authorization: `Bearer ${config.token}`,
13
13
  'Content-Type': 'application/json',
package/dist/index.d.ts CHANGED
@@ -1,23 +1,36 @@
1
1
  import { QuinnClientConfig } from './config';
2
2
  import { CompetenciesService } from './services/competencies';
3
+ import { CoursesService } from './services/courses';
3
4
  import { EndorsementsService } from './services/endorsements';
5
+ import { GroupsService } from './services/groups';
6
+ import { KnowledgeService } from './services/knowledge';
4
7
  import { LevelsService } from './services/levels';
5
8
  import { MembersService } from './services/members';
6
9
  import { OrganizationsService } from './services/organizations';
10
+ import { ProgressService } from './services/progress';
11
+ import { ProgramsService } from './services/programs';
7
12
  import { RolesService } from './services/roles';
8
13
  export * from './types';
9
14
  export { QuinnAuth } from './auth';
10
15
  export { DEFAULT_QUINN_API_URL, resolveApiUrl, resolveConfigPath, } from './config';
11
16
  export type { QuinnClientConfig } from './config';
17
+ export type { QuinnMutationAccess } from './mutation-access';
18
+ export { QuinnMutationAccessError } from './mutation-access';
19
+ export { KnowledgeDocumentsService, KnowledgeFoldersService, KnowledgeService, } from './services/knowledge';
12
20
  export declare class Quinn {
13
21
  private readonly config;
14
22
  private readonly http;
15
23
  readonly organizations: OrganizationsService;
24
+ readonly knowledge: KnowledgeService;
16
25
  readonly members: MembersService;
17
26
  readonly roles: RolesService;
18
27
  readonly levels: LevelsService;
19
28
  readonly competencies: CompetenciesService;
29
+ readonly courses: CoursesService;
30
+ readonly groups: GroupsService;
31
+ readonly programs: ProgramsService;
32
+ readonly progress: ProgressService;
20
33
  readonly endorsements: EndorsementsService;
21
34
  constructor(config?: QuinnClientConfig);
22
- private orgPath;
35
+ private assertMutationAllowed;
23
36
  }
package/dist/index.js CHANGED
@@ -14,14 +14,20 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.Quinn = exports.resolveConfigPath = exports.resolveApiUrl = exports.DEFAULT_QUINN_API_URL = exports.QuinnAuth = void 0;
17
+ exports.Quinn = exports.KnowledgeService = exports.KnowledgeFoldersService = exports.KnowledgeDocumentsService = exports.QuinnMutationAccessError = exports.resolveConfigPath = exports.resolveApiUrl = exports.DEFAULT_QUINN_API_URL = exports.QuinnAuth = void 0;
18
18
  const config_1 = require("./config");
19
19
  const http_1 = require("./http");
20
+ const mutation_access_1 = require("./mutation-access");
20
21
  const competencies_1 = require("./services/competencies");
22
+ const courses_1 = require("./services/courses");
21
23
  const endorsements_1 = require("./services/endorsements");
24
+ const groups_1 = require("./services/groups");
25
+ const knowledge_1 = require("./services/knowledge");
22
26
  const levels_1 = require("./services/levels");
23
27
  const members_1 = require("./services/members");
24
28
  const organizations_1 = require("./services/organizations");
29
+ const progress_1 = require("./services/progress");
30
+ const programs_1 = require("./services/programs");
25
31
  const roles_1 = require("./services/roles");
26
32
  __exportStar(require("./types"), exports);
27
33
  var auth_1 = require("./auth");
@@ -30,27 +36,49 @@ var config_2 = require("./config");
30
36
  Object.defineProperty(exports, "DEFAULT_QUINN_API_URL", { enumerable: true, get: function () { return config_2.DEFAULT_QUINN_API_URL; } });
31
37
  Object.defineProperty(exports, "resolveApiUrl", { enumerable: true, get: function () { return config_2.resolveApiUrl; } });
32
38
  Object.defineProperty(exports, "resolveConfigPath", { enumerable: true, get: function () { return config_2.resolveConfigPath; } });
39
+ var mutation_access_2 = require("./mutation-access");
40
+ Object.defineProperty(exports, "QuinnMutationAccessError", { enumerable: true, get: function () { return mutation_access_2.QuinnMutationAccessError; } });
41
+ var knowledge_2 = require("./services/knowledge");
42
+ Object.defineProperty(exports, "KnowledgeDocumentsService", { enumerable: true, get: function () { return knowledge_2.KnowledgeDocumentsService; } });
43
+ Object.defineProperty(exports, "KnowledgeFoldersService", { enumerable: true, get: function () { return knowledge_2.KnowledgeFoldersService; } });
44
+ Object.defineProperty(exports, "KnowledgeService", { enumerable: true, get: function () { return knowledge_2.KnowledgeService; } });
33
45
  class Quinn {
34
46
  config;
35
47
  http;
36
48
  organizations;
49
+ knowledge;
37
50
  members;
38
51
  roles;
39
52
  levels;
40
53
  competencies;
54
+ courses;
55
+ groups;
56
+ programs;
57
+ progress;
41
58
  endorsements;
42
59
  constructor(config = {}) {
43
60
  this.config = (0, config_1.resolveQuinnConfig)(config);
44
61
  this.http =
45
62
  this.config.httpClient ??
46
- (0, http_1.createQuinnHttpClient)({ apiUrl: this.config.apiUrl, token: this.config.token });
47
- this.organizations = new organizations_1.OrganizationsService(this.http, this.orgPath);
48
- this.members = new members_1.MembersService(this.http, this.orgPath);
49
- this.roles = new roles_1.RolesService(this.http, this.orgPath);
50
- this.levels = new levels_1.LevelsService(this.http, this.orgPath);
51
- this.competencies = new competencies_1.CompetenciesService(this.http, this.orgPath);
52
- this.endorsements = new endorsements_1.EndorsementsService(this.http, this.orgPath);
63
+ (0, http_1.createQuinnHttpClient)({
64
+ apiUrl: this.config.apiUrl,
65
+ token: this.config.token,
66
+ orgId: this.config.orgId,
67
+ });
68
+ this.organizations = new organizations_1.OrganizationsService(this.http, this.assertMutationAllowed);
69
+ this.knowledge = new knowledge_1.KnowledgeService(this.http);
70
+ this.members = new members_1.MembersService(this.http, this.assertMutationAllowed);
71
+ this.roles = new roles_1.RolesService(this.http);
72
+ this.levels = new levels_1.LevelsService(this.http);
73
+ this.competencies = new competencies_1.CompetenciesService(this.http);
74
+ this.courses = new courses_1.CoursesService(this.http);
75
+ this.groups = new groups_1.GroupsService(this.http);
76
+ this.programs = new programs_1.ProgramsService(this.http);
77
+ this.progress = new progress_1.ProgressService(this.http);
78
+ this.endorsements = new endorsements_1.EndorsementsService(this.http, this.assertMutationAllowed);
53
79
  }
54
- orgPath = () => `/platform/v1/orgs/${this.config.orgId}`;
80
+ assertMutationAllowed = (operation) => {
81
+ (0, mutation_access_1.assertMutationAllowed)(this.config.mutationAccess, operation);
82
+ };
55
83
  }
56
84
  exports.Quinn = Quinn;
@@ -0,0 +1,13 @@
1
+ export type QuinnMutationAccess = 'read_only' | 'needs_confirmation' | 'full_access';
2
+ export declare class QuinnMutationAccessError extends Error {
3
+ readonly access: QuinnMutationAccess;
4
+ readonly operation: string;
5
+ readonly code: 'MUTATION_BLOCKED' | 'MUTATION_CONFIRMATION_REQUIRED';
6
+ constructor(input: {
7
+ access: QuinnMutationAccess;
8
+ operation: string;
9
+ code: 'MUTATION_BLOCKED' | 'MUTATION_CONFIRMATION_REQUIRED';
10
+ message: string;
11
+ });
12
+ }
13
+ export declare function assertMutationAllowed(access: QuinnMutationAccess, operation: string): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuinnMutationAccessError = void 0;
4
+ exports.assertMutationAllowed = assertMutationAllowed;
5
+ class QuinnMutationAccessError extends Error {
6
+ access;
7
+ operation;
8
+ code;
9
+ constructor(input) {
10
+ super(input.message);
11
+ this.name = 'QuinnMutationAccessError';
12
+ this.access = input.access;
13
+ this.operation = input.operation;
14
+ this.code = input.code;
15
+ }
16
+ }
17
+ exports.QuinnMutationAccessError = QuinnMutationAccessError;
18
+ function assertMutationAllowed(access, operation) {
19
+ if (access === 'full_access') {
20
+ return;
21
+ }
22
+ if (access === 'needs_confirmation') {
23
+ throw new QuinnMutationAccessError({
24
+ access,
25
+ operation,
26
+ code: 'MUTATION_CONFIRMATION_REQUIRED',
27
+ message: `Quinn SDK mutation requires confirmation before executing "${operation}".`,
28
+ });
29
+ }
30
+ throw new QuinnMutationAccessError({
31
+ access,
32
+ operation,
33
+ code: 'MUTATION_BLOCKED',
34
+ message: `Quinn SDK mutation blocked because mutationAccess is "${access}" for "${operation}".`,
35
+ });
36
+ }
@@ -2,8 +2,7 @@ import { AxiosInstance } from 'axios';
2
2
  import { CompetenciesListQuery, Competency, Course, PagedResult } from '../types';
3
3
  export declare class CompetenciesService {
4
4
  private readonly http;
5
- private readonly orgPath;
6
- constructor(http: AxiosInstance, orgPath: () => string);
5
+ constructor(http: AxiosInstance);
7
6
  list(query: CompetenciesListQuery): Promise<PagedResult<Competency>>;
8
7
  get(id: string): Promise<Competency | null>;
9
8
  batchGet(ids: string[]): Promise<Competency[]>;
@@ -3,25 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CompetenciesService = void 0;
4
4
  class CompetenciesService {
5
5
  http;
6
- orgPath;
7
- constructor(http, orgPath) {
6
+ constructor(http) {
8
7
  this.http = http;
9
- this.orgPath = orgPath;
10
8
  }
11
9
  async list(query) {
12
- const resp = await this.http.get(`${this.orgPath()}/competencies`, { params: query });
10
+ const resp = await this.http.get('/competencies', { params: query });
13
11
  return resp.data;
14
12
  }
15
13
  async get(id) {
16
- const resp = await this.http.get(`${this.orgPath()}/competencies/${id}`);
14
+ const resp = await this.http.get(`/competencies/${id}`);
17
15
  return resp.data.item;
18
16
  }
19
17
  async batchGet(ids) {
20
- const resp = await this.http.post(`${this.orgPath()}/competencies/batch`, { ids });
18
+ const resp = await this.http.post('/competencies/batch', { ids });
21
19
  return resp.data.items;
22
20
  }
23
21
  async listCourses(id) {
24
- const resp = await this.http.get(`${this.orgPath()}/competencies/${id}/courses`);
22
+ const resp = await this.http.get(`/competencies/${id}/courses`);
25
23
  return resp.data.items;
26
24
  }
27
25
  }
@@ -0,0 +1,12 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { Course, PagedResult } from '../types';
3
+ export declare class CoursesService {
4
+ private readonly http;
5
+ constructor(http: AxiosInstance);
6
+ list(query?: {
7
+ limit?: number;
8
+ token?: string;
9
+ }): Promise<PagedResult<Course>>;
10
+ get(id: string): Promise<Course | null>;
11
+ batchGet(ids: string[]): Promise<Course[]>;
12
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CoursesService = void 0;
4
+ class CoursesService {
5
+ http;
6
+ constructor(http) {
7
+ this.http = http;
8
+ }
9
+ async list(query = {}) {
10
+ const resp = await this.http.get('/courses', { params: query });
11
+ return resp.data;
12
+ }
13
+ async get(id) {
14
+ const resp = await this.http.get(`/courses/${id}`);
15
+ return resp.data.item;
16
+ }
17
+ async batchGet(ids) {
18
+ const resp = await this.http.post('/courses/batch', { ids });
19
+ return resp.data.items;
20
+ }
21
+ }
22
+ exports.CoursesService = CoursesService;
@@ -1,10 +1,12 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { Endorsement, ListEndorsementsInput } from '../types';
2
+ import { EndorseCompetencyInput, Endorsement, ListEndorsementsInput, ResetEndorsementInput } from '../types';
3
3
  export declare class EndorsementsService {
4
4
  private readonly http;
5
- private readonly orgPath;
6
- constructor(http: AxiosInstance, orgPath: () => string);
5
+ private readonly assertMutationAllowed;
6
+ constructor(http: AxiosInstance, assertMutationAllowed: (operation: string) => void);
7
7
  get(id: string): Promise<Endorsement | null>;
8
8
  find(uid: string, competencyId: string): Promise<Endorsement | null>;
9
9
  list(input: ListEndorsementsInput): Promise<Endorsement[]>;
10
+ endorse(input: EndorseCompetencyInput): Promise<Endorsement | null>;
11
+ reset(input: ResetEndorsementInput): Promise<Endorsement | null>;
10
12
  }
@@ -3,22 +3,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EndorsementsService = void 0;
4
4
  class EndorsementsService {
5
5
  http;
6
- orgPath;
7
- constructor(http, orgPath) {
6
+ assertMutationAllowed;
7
+ constructor(http, assertMutationAllowed) {
8
8
  this.http = http;
9
- this.orgPath = orgPath;
9
+ this.assertMutationAllowed = assertMutationAllowed;
10
10
  }
11
11
  async get(id) {
12
- const resp = await this.http.get(`${this.orgPath()}/endorsements/${id}`);
12
+ const resp = await this.http.get(`/endorsements/${id}`);
13
13
  return resp.data.item;
14
14
  }
15
15
  async find(uid, competencyId) {
16
- const resp = await this.http.get(`${this.orgPath()}/endorsements/find`, { params: { uid, competencyId } });
16
+ const resp = await this.http.get('/endorsements/find', { params: { uid, competencyId } });
17
17
  return resp.data.item;
18
18
  }
19
19
  async list(input) {
20
- const resp = await this.http.post(`${this.orgPath()}/endorsements/list`, input);
20
+ const resp = await this.http.post('/endorsements/list', input);
21
21
  return resp.data.items;
22
22
  }
23
+ async endorse(input) {
24
+ this.assertMutationAllowed('endorsements.endorse');
25
+ const resp = await this.http.post('/endorsements/endorse', input);
26
+ return resp.data.item;
27
+ }
28
+ async reset(input) {
29
+ this.assertMutationAllowed('endorsements.reset');
30
+ const resp = await this.http.post('/endorsements/reset', input);
31
+ return resp.data.item;
32
+ }
23
33
  }
24
34
  exports.EndorsementsService = EndorsementsService;
@@ -0,0 +1,10 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { Group, GroupMember } from '../types';
3
+ export declare class GroupsService {
4
+ private readonly http;
5
+ constructor(http: AxiosInstance);
6
+ list(): Promise<Group[]>;
7
+ get(id: string): Promise<Group | null>;
8
+ batchGet(ids: string[]): Promise<Group[]>;
9
+ listMembers(groupId: string): Promise<GroupMember[]>;
10
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GroupsService = void 0;
4
+ class GroupsService {
5
+ http;
6
+ constructor(http) {
7
+ this.http = http;
8
+ }
9
+ async list() {
10
+ const resp = await this.http.get('/groups');
11
+ return resp.data.items;
12
+ }
13
+ async get(id) {
14
+ const resp = await this.http.get(`/groups/${id}`);
15
+ return resp.data.item;
16
+ }
17
+ async batchGet(ids) {
18
+ const resp = await this.http.post('/groups/batch', { ids });
19
+ return resp.data.items;
20
+ }
21
+ async listMembers(groupId) {
22
+ const resp = await this.http.get(`/groups/${groupId}/members`);
23
+ return resp.data.items;
24
+ }
25
+ }
26
+ exports.GroupsService = GroupsService;
@@ -0,0 +1,24 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { GetDocumentTranscriptResponse, KnowledgeDocument, KnowledgeDocumentsListQuery, KnowledgeFolder, KnowledgeFoldersListQuery, KnowledgeSearchHit, KnowledgeSearchInput, PagedResult } from '../types';
3
+ export declare class KnowledgeDocumentsService {
4
+ private readonly http;
5
+ constructor(http: AxiosInstance);
6
+ list(query?: KnowledgeDocumentsListQuery): Promise<PagedResult<KnowledgeDocument>>;
7
+ get(id: string): Promise<KnowledgeDocument | null>;
8
+ getTranscript(id: string): Promise<GetDocumentTranscriptResponse>;
9
+ }
10
+ export declare class KnowledgeFoldersService {
11
+ private readonly http;
12
+ constructor(http: AxiosInstance);
13
+ list(query?: KnowledgeFoldersListQuery): Promise<{
14
+ items: KnowledgeFolder[];
15
+ }>;
16
+ get(id: string): Promise<KnowledgeFolder | null>;
17
+ }
18
+ export declare class KnowledgeService {
19
+ private readonly http;
20
+ readonly documents: KnowledgeDocumentsService;
21
+ readonly folders: KnowledgeFoldersService;
22
+ constructor(http: AxiosInstance);
23
+ search(input: KnowledgeSearchInput): Promise<KnowledgeSearchHit[]>;
24
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KnowledgeService = exports.KnowledgeFoldersService = exports.KnowledgeDocumentsService = void 0;
4
+ class KnowledgeDocumentsService {
5
+ http;
6
+ constructor(http) {
7
+ this.http = http;
8
+ }
9
+ async list(query = {}) {
10
+ const resp = await this.http.get('/knowledge/documents', { params: query });
11
+ return resp.data;
12
+ }
13
+ async get(id) {
14
+ const resp = await this.http.get(`/knowledge/documents/${id}`);
15
+ return resp.data.item;
16
+ }
17
+ async getTranscript(id) {
18
+ const resp = await this.http.get(`/knowledge/documents/${id}/transcript`);
19
+ return resp.data;
20
+ }
21
+ }
22
+ exports.KnowledgeDocumentsService = KnowledgeDocumentsService;
23
+ class KnowledgeFoldersService {
24
+ http;
25
+ constructor(http) {
26
+ this.http = http;
27
+ }
28
+ async list(query = {}) {
29
+ const resp = await this.http.get('/knowledge/folders', { params: query });
30
+ return resp.data;
31
+ }
32
+ async get(id) {
33
+ const resp = await this.http.get(`/knowledge/folders/${id}`);
34
+ return resp.data.item;
35
+ }
36
+ }
37
+ exports.KnowledgeFoldersService = KnowledgeFoldersService;
38
+ class KnowledgeService {
39
+ http;
40
+ documents;
41
+ folders;
42
+ constructor(http) {
43
+ this.http = http;
44
+ this.documents = new KnowledgeDocumentsService(http);
45
+ this.folders = new KnowledgeFoldersService(http);
46
+ }
47
+ async search(input) {
48
+ const resp = await this.http.post('/knowledge/search', input);
49
+ return resp.data.items;
50
+ }
51
+ }
52
+ exports.KnowledgeService = KnowledgeService;
@@ -2,8 +2,7 @@ import { AxiosInstance } from 'axios';
2
2
  import { Level, LevelsListQuery, PagedResult } from '../types';
3
3
  export declare class LevelsService {
4
4
  private readonly http;
5
- private readonly orgPath;
6
- constructor(http: AxiosInstance, orgPath: () => string);
5
+ constructor(http: AxiosInstance);
7
6
  list(query: LevelsListQuery): Promise<PagedResult<Level>>;
8
7
  get(id: string): Promise<Level | null>;
9
8
  batchGet(ids: string[]): Promise<Level[]>;
@@ -3,23 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LevelsService = void 0;
4
4
  class LevelsService {
5
5
  http;
6
- orgPath;
7
- constructor(http, orgPath) {
6
+ constructor(http) {
8
7
  this.http = http;
9
- this.orgPath = orgPath;
10
8
  }
11
9
  async list(query) {
12
- const resp = await this.http.get(`${this.orgPath()}/levels`, {
10
+ const resp = await this.http.get('/levels', {
13
11
  params: query,
14
12
  });
15
13
  return resp.data;
16
14
  }
17
15
  async get(id) {
18
- const resp = await this.http.get(`${this.orgPath()}/levels/${id}`);
16
+ const resp = await this.http.get(`/levels/${id}`);
19
17
  return resp.data.item;
20
18
  }
21
19
  async batchGet(ids) {
22
- const resp = await this.http.post(`${this.orgPath()}/levels/batch`, { ids });
20
+ const resp = await this.http.post('/levels/batch', { ids });
23
21
  return resp.data.items;
24
22
  }
25
23
  }
@@ -1,9 +1,9 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { Member, MembersBatchGetInput, MembersListQuery, PagedResult } from '../types';
2
+ import { MembersBatchDeleteInput, Member, MembersBatchGetInput, MembersCreateInput, MembersListQuery, MembersUpdateManagerInput, MembersUpdateProfileInput, MembersUpdatePrivilegeInput, MembersUpdateRolesInput, PagedResult } from '../types';
3
3
  export declare class MembersService {
4
4
  private readonly http;
5
- private readonly orgPath;
6
- constructor(http: AxiosInstance, orgPath: () => string);
5
+ private readonly assertMutationAllowed;
6
+ constructor(http: AxiosInstance, assertMutationAllowed: (operation: string) => void);
7
7
  list(query?: MembersListQuery): Promise<PagedResult<Member>>;
8
8
  listManagers(query?: {
9
9
  limit?: number;
@@ -12,4 +12,11 @@ export declare class MembersService {
12
12
  }): Promise<PagedResult<Member>>;
13
13
  get(id: string): Promise<Member | null>;
14
14
  batchGet(input: string[] | MembersBatchGetInput): Promise<Member[]>;
15
+ delete(memberId: string): Promise<void>;
16
+ batchDelete(input: string[] | MembersBatchDeleteInput): Promise<void>;
17
+ create(input: MembersCreateInput): Promise<Member | null>;
18
+ updatePrivilege(input: MembersUpdatePrivilegeInput): Promise<Member | null>;
19
+ updateRoles(input: MembersUpdateRolesInput): Promise<Member | null>;
20
+ updateManager(input: MembersUpdateManagerInput): Promise<Member | null>;
21
+ updateProfile(input: MembersUpdateProfileInput): Promise<Member | null>;
15
22
  }
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MembersService = void 0;
4
4
  class MembersService {
5
5
  http;
6
- orgPath;
7
- constructor(http, orgPath) {
6
+ assertMutationAllowed;
7
+ constructor(http, assertMutationAllowed) {
8
8
  this.http = http;
9
- this.orgPath = orgPath;
9
+ this.assertMutationAllowed = assertMutationAllowed;
10
10
  }
11
11
  async list(query = {}) {
12
12
  const params = {
@@ -18,23 +18,65 @@ class MembersService {
18
18
  ? query.privilege.join(',')
19
19
  : query.privilege,
20
20
  };
21
- const resp = await this.http.get(`${this.orgPath()}/members`, { params });
21
+ const resp = await this.http.get('/members', { params });
22
22
  return resp.data;
23
23
  }
24
24
  async listManagers(query = {}) {
25
- const resp = await this.http.get(`${this.orgPath()}/members/managers`, { params: query });
25
+ const resp = await this.http.get('/members/managers', {
26
+ params: query,
27
+ });
26
28
  return resp.data;
27
29
  }
28
30
  async get(id) {
29
- const resp = await this.http.get(`${this.orgPath()}/members/${id}`);
31
+ const resp = await this.http.get(`/members/${id}`);
30
32
  return resp.data.item;
31
33
  }
32
34
  async batchGet(input) {
33
35
  const body = Array.isArray(input)
34
36
  ? { ids: input }
35
37
  : input;
36
- const resp = await this.http.post(`${this.orgPath()}/members/batch`, body);
38
+ const resp = await this.http.post('/members/batch', body);
37
39
  return resp.data.items;
38
40
  }
41
+ async delete(memberId) {
42
+ this.assertMutationAllowed('members.delete');
43
+ await this.http.delete(`/members/${memberId}`);
44
+ }
45
+ async batchDelete(input) {
46
+ this.assertMutationAllowed('members.batchDelete');
47
+ const body = Array.isArray(input)
48
+ ? { uids: input }
49
+ : input;
50
+ await this.http.post('/members/batch-delete', body);
51
+ }
52
+ async create(input) {
53
+ this.assertMutationAllowed('members.create');
54
+ const resp = await this.http.post('/members', input);
55
+ return resp.data.item;
56
+ }
57
+ async updatePrivilege(input) {
58
+ this.assertMutationAllowed('members.updatePrivilege');
59
+ const resp = await this.http.patch(`/members/${input.memberId}/privilege`, { privilege: input.privilege });
60
+ return resp.data.item;
61
+ }
62
+ async updateRoles(input) {
63
+ this.assertMutationAllowed('members.updateRoles');
64
+ const resp = await this.http.put(`/members/${input.memberId}/roles`, { roleIds: input.roleIds });
65
+ return resp.data.item;
66
+ }
67
+ async updateManager(input) {
68
+ this.assertMutationAllowed('members.updateManager');
69
+ const resp = await this.http.put(`/members/${input.memberId}/manager`, { managerUid: input.managerUid });
70
+ return resp.data.item;
71
+ }
72
+ async updateProfile(input) {
73
+ this.assertMutationAllowed('members.updateProfile');
74
+ const resp = await this.http.patch(`/members/${input.memberId}/profile`, {
75
+ firstName: input.firstName,
76
+ lastName: input.lastName,
77
+ phoneNumber: input.phoneNumber,
78
+ });
79
+ return resp.data.item;
80
+ }
39
81
  }
40
82
  exports.MembersService = MembersService;
@@ -1,8 +1,9 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { OrganizationDetails } from '../types';
2
+ import { OrganizationDetails, OrganizationUpdateInput } from '../types';
3
3
  export declare class OrganizationsService {
4
4
  private readonly http;
5
- private readonly orgPath;
6
- constructor(http: AxiosInstance, orgPath: () => string);
5
+ private readonly assertMutationAllowed;
6
+ constructor(http: AxiosInstance, assertMutationAllowed: (operation: string) => void);
7
7
  current(): Promise<OrganizationDetails>;
8
+ update(input: OrganizationUpdateInput): Promise<OrganizationDetails>;
8
9
  }
@@ -3,13 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OrganizationsService = void 0;
4
4
  class OrganizationsService {
5
5
  http;
6
- orgPath;
7
- constructor(http, orgPath) {
6
+ assertMutationAllowed;
7
+ constructor(http, assertMutationAllowed) {
8
8
  this.http = http;
9
- this.orgPath = orgPath;
9
+ this.assertMutationAllowed = assertMutationAllowed;
10
10
  }
11
11
  async current() {
12
- const resp = await this.http.get(this.orgPath());
12
+ const resp = await this.http.get('/');
13
+ return resp.data.item;
14
+ }
15
+ async update(input) {
16
+ this.assertMutationAllowed('organizations.update');
17
+ const resp = await this.http.patch('/', input);
13
18
  return resp.data.item;
14
19
  }
15
20
  }
@@ -0,0 +1,12 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { PagedResult, Program } from '../types';
3
+ export declare class ProgramsService {
4
+ private readonly http;
5
+ constructor(http: AxiosInstance);
6
+ list(query?: {
7
+ limit?: number;
8
+ token?: string;
9
+ }): Promise<PagedResult<Program>>;
10
+ get(id: string): Promise<Program | null>;
11
+ batchGet(ids: string[]): Promise<Program[]>;
12
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProgramsService = void 0;
4
+ class ProgramsService {
5
+ http;
6
+ constructor(http) {
7
+ this.http = http;
8
+ }
9
+ async list(query = {}) {
10
+ const resp = await this.http.get('/programs', { params: query });
11
+ return resp.data;
12
+ }
13
+ async get(id) {
14
+ const resp = await this.http.get(`/programs/${id}`);
15
+ return resp.data.item;
16
+ }
17
+ async batchGet(ids) {
18
+ const resp = await this.http.post('/programs/batch', { ids });
19
+ return resp.data.items;
20
+ }
21
+ }
22
+ exports.ProgramsService = ProgramsService;
@@ -0,0 +1,10 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { Progress, ProgressesBatchQueryInputItem, ProgressesListInput, ProgressSummary } from '../types';
3
+ export declare class ProgressService {
4
+ private readonly http;
5
+ constructor(http: AxiosInstance);
6
+ list(input: ProgressesListInput): Promise<Progress[]>;
7
+ batchQuery(items: ProgressesBatchQueryInputItem[]): Promise<Progress[]>;
8
+ summary(input: ProgressesListInput): Promise<ProgressSummary>;
9
+ courseSummary(courseId: string): Promise<ProgressSummary>;
10
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProgressService = void 0;
4
+ class ProgressService {
5
+ http;
6
+ constructor(http) {
7
+ this.http = http;
8
+ }
9
+ async list(input) {
10
+ const params = {
11
+ userIds: input.userIds?.join(','),
12
+ courseIds: input.courseIds?.join(','),
13
+ };
14
+ const resp = await this.http.get('/progress', { params });
15
+ return resp.data.items;
16
+ }
17
+ async batchQuery(items) {
18
+ const resp = await this.http.post('/progress/batch', { items });
19
+ return resp.data.items;
20
+ }
21
+ async summary(input) {
22
+ const params = {
23
+ userIds: input.userIds?.join(','),
24
+ courseIds: input.courseIds?.join(','),
25
+ };
26
+ const resp = await this.http.get('/progress/summary', { params });
27
+ return resp.data.item;
28
+ }
29
+ async courseSummary(courseId) {
30
+ const resp = await this.http.get(`/progress/summary/courses/${courseId}`);
31
+ return resp.data.item;
32
+ }
33
+ }
34
+ exports.ProgressService = ProgressService;
@@ -2,8 +2,7 @@ import { AxiosInstance } from 'axios';
2
2
  import { Role } from '../types';
3
3
  export declare class RolesService {
4
4
  private readonly http;
5
- private readonly orgPath;
6
- constructor(http: AxiosInstance, orgPath: () => string);
5
+ constructor(http: AxiosInstance);
7
6
  list(): Promise<Role[]>;
8
7
  get(id: string): Promise<Role | null>;
9
8
  batchGet(ids: string[]): Promise<Role[]>;
@@ -3,21 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RolesService = void 0;
4
4
  class RolesService {
5
5
  http;
6
- orgPath;
7
- constructor(http, orgPath) {
6
+ constructor(http) {
8
7
  this.http = http;
9
- this.orgPath = orgPath;
10
8
  }
11
9
  async list() {
12
- const resp = await this.http.get(`${this.orgPath()}/roles`);
10
+ const resp = await this.http.get('/roles');
13
11
  return resp.data.items;
14
12
  }
15
13
  async get(id) {
16
- const resp = await this.http.get(`${this.orgPath()}/roles/${id}`);
14
+ const resp = await this.http.get(`/roles/${id}`);
17
15
  return resp.data.item;
18
16
  }
19
17
  async batchGet(ids) {
20
- const resp = await this.http.post(`${this.orgPath()}/roles/batch`, { ids });
18
+ const resp = await this.http.post('/roles/batch', { ids });
21
19
  return resp.data.items;
22
20
  }
23
21
  }
package/dist/types.d.ts CHANGED
@@ -10,6 +10,11 @@ export interface PagedResult<T> {
10
10
  export interface Organization {
11
11
  id: string;
12
12
  name: string;
13
+ brandColor: string;
14
+ logo: {
15
+ id: string;
16
+ url: string;
17
+ } | null;
13
18
  }
14
19
  export interface OrganizationDetails {
15
20
  organization: Organization | null;
@@ -21,6 +26,11 @@ export interface OrganizationDetails {
21
26
  competencies: number;
22
27
  };
23
28
  }
29
+ export interface OrganizationUpdateInput {
30
+ name?: string;
31
+ logoId?: string;
32
+ brandColor?: string;
33
+ }
24
34
  export interface Member {
25
35
  userId: string;
26
36
  email: string;
@@ -42,6 +52,33 @@ export interface MembersBatchGetInput {
42
52
  ids?: string[];
43
53
  emails?: string[];
44
54
  }
55
+ export interface MembersBatchDeleteInput {
56
+ uids: string[];
57
+ }
58
+ export interface MembersCreateInput {
59
+ email: string;
60
+ firstName: string;
61
+ lastName: string;
62
+ sendInvite?: boolean;
63
+ }
64
+ export interface MembersUpdatePrivilegeInput {
65
+ memberId: string;
66
+ privilege: Privilege;
67
+ }
68
+ export interface MembersUpdateRolesInput {
69
+ memberId: string;
70
+ roleIds: string[];
71
+ }
72
+ export interface MembersUpdateManagerInput {
73
+ memberId: string;
74
+ managerUid: string;
75
+ }
76
+ export interface MembersUpdateProfileInput {
77
+ memberId: string;
78
+ firstName?: string;
79
+ lastName?: string;
80
+ phoneNumber?: string;
81
+ }
45
82
  export interface Role {
46
83
  id: string;
47
84
  label: string;
@@ -85,6 +122,98 @@ export interface Course {
85
122
  creatorUid: string;
86
123
  createdAt: string;
87
124
  }
125
+ export interface KnowledgeSearchInput {
126
+ query: string;
127
+ folderId?: string;
128
+ size?: number;
129
+ }
130
+ export interface KnowledgeSearchHit {
131
+ id: string;
132
+ type: string;
133
+ text: string;
134
+ metadata?: Record<string, unknown>;
135
+ }
136
+ export interface KnowledgeDocument {
137
+ id: string;
138
+ name: string;
139
+ uid: string;
140
+ orgId: string;
141
+ parentId: string;
142
+ parentType: string;
143
+ status: string;
144
+ extFileId: string | null;
145
+ contentType: string | null;
146
+ originalContentLength: number;
147
+ contentLength: number;
148
+ downloadable: boolean;
149
+ folderId: string | null;
150
+ createdAt: string;
151
+ updatedAt: string;
152
+ }
153
+ export interface KnowledgeDocumentsListQuery extends PaginationQuery {
154
+ folderId?: string;
155
+ name?: string;
156
+ includePackFiles?: boolean;
157
+ }
158
+ export interface GetDocumentTranscriptResponse {
159
+ content: string;
160
+ }
161
+ export interface KnowledgeFolder {
162
+ id: string;
163
+ orgId: string;
164
+ name: string;
165
+ parentId: string | null;
166
+ createdBy: string;
167
+ children?: KnowledgeFolder[];
168
+ createdAt: string;
169
+ updatedAt: string;
170
+ }
171
+ export interface KnowledgeFoldersListQuery {
172
+ parentId?: string;
173
+ }
174
+ export interface Group {
175
+ id: string;
176
+ name: string;
177
+ creatorUid: string;
178
+ createdAt: string;
179
+ }
180
+ export interface GroupMember {
181
+ groupId: string;
182
+ userId: string;
183
+ addedByUid: string;
184
+ addedAt: string;
185
+ }
186
+ export interface Program {
187
+ id: string;
188
+ name: string;
189
+ creatorUid: string;
190
+ createdAt: string;
191
+ settings?: {
192
+ managerOnlyEndorsement: boolean;
193
+ };
194
+ }
195
+ export interface Progress {
196
+ id: string;
197
+ userId: string;
198
+ courseId: string;
199
+ progressPct: number;
200
+ completedAt: string | null;
201
+ score: number | null;
202
+ }
203
+ export interface ProgressSummary {
204
+ total: number;
205
+ numCompleted: number;
206
+ numInProgress: number;
207
+ numNotStarted: number;
208
+ }
209
+ export interface ProgressesListInput {
210
+ userIds?: string[];
211
+ courseIds?: string[];
212
+ }
213
+ export interface ProgressesBatchQueryInputItem {
214
+ userId: string;
215
+ courseId: string;
216
+ }
88
217
  export interface Endorsement {
89
218
  id: string;
90
219
  uid: string;
@@ -105,3 +234,13 @@ export interface ListEndorsementsInput {
105
234
  uids: string[];
106
235
  competencyIds: string[];
107
236
  }
237
+ export interface EndorseCompetencyInput {
238
+ uid: string;
239
+ competencyId: string;
240
+ note?: string;
241
+ }
242
+ export interface ResetEndorsementInput {
243
+ uid: string;
244
+ competencyId: string;
245
+ reason: string;
246
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totoday/quinn-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [