@headless-lms/core 0.1.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/LICENSE +21 -0
- package/dist/assets/events.d.ts +81 -0
- package/dist/assets/events.js +24 -0
- package/dist/assets/events.js.map +1 -0
- package/dist/assets/index.d.ts +7 -0
- package/dist/assets/index.js +3 -0
- package/dist/assets/model.d.ts +4 -0
- package/dist/assets/model.js +1 -0
- package/dist/assets/ports.d.ts +34 -0
- package/dist/assets/ports.js +1 -0
- package/dist/assets/service.d.ts +29 -0
- package/dist/assets/service.js +130 -0
- package/dist/assets/service.js.map +1 -0
- package/dist/automations/actions.d.ts +24 -0
- package/dist/automations/actions.js +59 -0
- package/dist/automations/actions.js.map +1 -0
- package/dist/automations/catalog.d.ts +12 -0
- package/dist/automations/catalog.js +224 -0
- package/dist/automations/catalog.js.map +1 -0
- package/dist/automations/events.d.ts +264 -0
- package/dist/automations/events.js +54 -0
- package/dist/automations/events.js.map +1 -0
- package/dist/automations/index.d.ts +9 -0
- package/dist/automations/index.js +4 -0
- package/dist/automations/model.d.ts +12 -0
- package/dist/automations/model.js +14 -0
- package/dist/automations/model.js.map +1 -0
- package/dist/automations/ports.d.ts +56 -0
- package/dist/automations/ports.js +1 -0
- package/dist/automations/service.d.ts +53 -0
- package/dist/automations/service.js +225 -0
- package/dist/automations/service.js.map +1 -0
- package/dist/automations/types.d.ts +3 -0
- package/dist/automations/types.js +1 -0
- package/dist/content/events.d.ts +410 -0
- package/dist/content/events.js +105 -0
- package/dist/content/events.js.map +1 -0
- package/dist/content/index.d.ts +8 -0
- package/dist/content/index.js +3 -0
- package/dist/content/model.d.ts +3 -0
- package/dist/content/model.js +1 -0
- package/dist/content/ports.d.ts +85 -0
- package/dist/content/ports.js +1 -0
- package/dist/content/service.d.ts +54 -0
- package/dist/content/service.js +479 -0
- package/dist/content/service.js.map +1 -0
- package/dist/content/types.d.ts +4 -0
- package/dist/content/types.js +1 -0
- package/dist/discussion/events.d.ts +101 -0
- package/dist/discussion/events.js +29 -0
- package/dist/discussion/events.js.map +1 -0
- package/dist/discussion/index.d.ts +8 -0
- package/dist/discussion/index.js +3 -0
- package/dist/discussion/model.d.ts +5 -0
- package/dist/discussion/model.js +1 -0
- package/dist/discussion/ports.d.ts +112 -0
- package/dist/discussion/ports.js +1 -0
- package/dist/discussion/service.d.ts +67 -0
- package/dist/discussion/service.js +343 -0
- package/dist/discussion/service.js.map +1 -0
- package/dist/discussion/types.d.ts +4 -0
- package/dist/discussion/types.js +1 -0
- package/dist/entitlements/events.d.ts +89 -0
- package/dist/entitlements/events.js +29 -0
- package/dist/entitlements/events.js.map +1 -0
- package/dist/entitlements/index.d.ts +7 -0
- package/dist/entitlements/index.js +3 -0
- package/dist/entitlements/model.d.ts +4 -0
- package/dist/entitlements/model.js +1 -0
- package/dist/entitlements/ports.d.ts +34 -0
- package/dist/entitlements/ports.js +1 -0
- package/dist/entitlements/service.d.ts +27 -0
- package/dist/entitlements/service.js +60 -0
- package/dist/entitlements/service.js.map +1 -0
- package/dist/identity/events.d.ts +63 -0
- package/dist/identity/events.js +24 -0
- package/dist/identity/events.js.map +1 -0
- package/dist/identity/index.d.ts +8 -0
- package/dist/identity/index.js +3 -0
- package/dist/identity/model.d.ts +3 -0
- package/dist/identity/model.js +1 -0
- package/dist/identity/ports.d.ts +58 -0
- package/dist/identity/ports.js +1 -0
- package/dist/identity/service.d.ts +38 -0
- package/dist/identity/service.js +79 -0
- package/dist/identity/service.js.map +1 -0
- package/dist/identity/types.d.ts +4 -0
- package/dist/identity/types.js +1 -0
- package/dist/integrations/events.d.ts +70 -0
- package/dist/integrations/events.js +24 -0
- package/dist/integrations/events.js.map +1 -0
- package/dist/integrations/index.d.ts +9 -0
- package/dist/integrations/index.js +6 -0
- package/dist/integrations/model.d.ts +28 -0
- package/dist/integrations/model.js +45 -0
- package/dist/integrations/model.js.map +1 -0
- package/dist/integrations/ports.d.ts +62 -0
- package/dist/integrations/ports.js +1 -0
- package/dist/integrations/registry.d.ts +7 -0
- package/dist/integrations/registry.js +16 -0
- package/dist/integrations/registry.js.map +1 -0
- package/dist/integrations/service.d.ts +47 -0
- package/dist/integrations/service.js +184 -0
- package/dist/integrations/service.js.map +1 -0
- package/dist/integrations/zod.d.ts +29 -0
- package/dist/integrations/zod.js +40 -0
- package/dist/integrations/zod.js.map +1 -0
- package/dist/organizations/events.d.ts +197 -0
- package/dist/organizations/events.js +59 -0
- package/dist/organizations/events.js.map +1 -0
- package/dist/organizations/index.d.ts +11 -0
- package/dist/organizations/index.js +5 -0
- package/dist/organizations/members.d.ts +32 -0
- package/dist/organizations/members.js +12 -0
- package/dist/organizations/members.js.map +1 -0
- package/dist/organizations/model.d.ts +3 -0
- package/dist/organizations/model.js +1 -0
- package/dist/organizations/ports.d.ts +127 -0
- package/dist/organizations/ports.js +1 -0
- package/dist/organizations/roles.d.ts +23 -0
- package/dist/organizations/roles.js +70 -0
- package/dist/organizations/roles.js.map +1 -0
- package/dist/organizations/service.d.ts +58 -0
- package/dist/organizations/service.js +359 -0
- package/dist/organizations/service.js.map +1 -0
- package/dist/organizations/types.d.ts +39 -0
- package/dist/organizations/types.js +1 -0
- package/dist/progress/events.d.ts +55 -0
- package/dist/progress/events.js +19 -0
- package/dist/progress/events.js.map +1 -0
- package/dist/progress/index.d.ts +8 -0
- package/dist/progress/index.js +3 -0
- package/dist/progress/model.d.ts +3 -0
- package/dist/progress/model.js +1 -0
- package/dist/progress/ports.d.ts +37 -0
- package/dist/progress/ports.js +1 -0
- package/dist/progress/service.d.ts +33 -0
- package/dist/progress/service.js +181 -0
- package/dist/progress/service.js.map +1 -0
- package/dist/progress/types.d.ts +4 -0
- package/dist/progress/types.js +1 -0
- package/dist/reporting/dashboard/index.d.ts +4 -0
- package/dist/reporting/dashboard/index.js +2 -0
- package/dist/reporting/dashboard/model.d.ts +14 -0
- package/dist/reporting/dashboard/model.js +1 -0
- package/dist/reporting/dashboard/ports.d.ts +13 -0
- package/dist/reporting/dashboard/ports.js +1 -0
- package/dist/reporting/dashboard/service.d.ts +19 -0
- package/dist/reporting/dashboard/service.js +20 -0
- package/dist/reporting/dashboard/service.js.map +1 -0
- package/dist/reporting/learn/index.d.ts +5 -0
- package/dist/reporting/learn/index.js +2 -0
- package/dist/reporting/learn/model.d.ts +23 -0
- package/dist/reporting/learn/model.js +1 -0
- package/dist/reporting/learn/ports.d.ts +42 -0
- package/dist/reporting/learn/ports.js +1 -0
- package/dist/reporting/learn/service.d.ts +48 -0
- package/dist/reporting/learn/service.js +111 -0
- package/dist/reporting/learn/service.js.map +1 -0
- package/dist/reporting/students/index.d.ts +4 -0
- package/dist/reporting/students/index.js +2 -0
- package/dist/reporting/students/model.d.ts +31 -0
- package/dist/reporting/students/model.js +1 -0
- package/dist/reporting/students/ports.d.ts +13 -0
- package/dist/reporting/students/ports.js +1 -0
- package/dist/reporting/students/service.d.ts +19 -0
- package/dist/reporting/students/service.js +20 -0
- package/dist/reporting/students/service.js.map +1 -0
- package/dist/shared/errors.d.ts +22 -0
- package/dist/shared/errors.js +34 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/events.d.ts +31 -0
- package/dist/shared/events.js +75 -0
- package/dist/shared/events.js.map +1 -0
- package/dist/shared/id.d.ts +44 -0
- package/dist/shared/id.js +53 -0
- package/dist/shared/id.js.map +1 -0
- package/dist/shared/invite-token.d.ts +9 -0
- package/dist/shared/invite-token.js +16 -0
- package/dist/shared/invite-token.js.map +1 -0
- package/dist/shared/logger.d.ts +19 -0
- package/dist/shared/logger.js +44 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/mailer.d.ts +23 -0
- package/dist/shared/mailer.js +27 -0
- package/dist/shared/mailer.js.map +1 -0
- package/dist/shared/ports.d.ts +62 -0
- package/dist/shared/ports.js +2 -0
- package/dist/shared/settings.d.ts +25 -0
- package/dist/shared/settings.js +21 -0
- package/dist/shared/settings.js.map +1 -0
- package/dist/types/assets.d.ts +2 -0
- package/dist/types/assets.js +1 -0
- package/dist/types/automations.d.ts +23 -0
- package/dist/types/automations.js +1 -0
- package/dist/types/content.d.ts +2 -0
- package/dist/types/content.js +1 -0
- package/dist/types/discussion.d.ts +36 -0
- package/dist/types/discussion.js +1 -0
- package/dist/types/email-templates.d.ts +57 -0
- package/dist/types/email-templates.js +1 -0
- package/dist/types/entitlements.d.ts +3 -0
- package/dist/types/entitlements.js +1 -0
- package/dist/types/events.d.ts +25 -0
- package/dist/types/events.js +1 -0
- package/dist/types/identity.d.ts +37 -0
- package/dist/types/identity.js +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.js +1 -0
- package/dist/types/integrations.d.ts +45 -0
- package/dist/types/integrations.js +1 -0
- package/dist/types/organizations.d.ts +15 -0
- package/dist/types/organizations.js +1 -0
- package/dist/types/ports.d.ts +57 -0
- package/dist/types/ports.js +1 -0
- package/dist/types/progress.d.ts +6 -0
- package/dist/types/progress.js +1 -0
- package/dist/types/schemas/assets.d.ts +109 -0
- package/dist/types/schemas/assets.js +49 -0
- package/dist/types/schemas/assets.js.map +1 -0
- package/dist/types/schemas/automations.d.ts +118 -0
- package/dist/types/schemas/automations.js +73 -0
- package/dist/types/schemas/automations.js.map +1 -0
- package/dist/types/schemas/content.d.ts +216 -0
- package/dist/types/schemas/content.js +138 -0
- package/dist/types/schemas/content.js.map +1 -0
- package/dist/types/schemas/credentials.d.ts +15 -0
- package/dist/types/schemas/credentials.js +15 -0
- package/dist/types/schemas/credentials.js.map +1 -0
- package/dist/types/schemas/discussion.d.ts +192 -0
- package/dist/types/schemas/discussion.js +100 -0
- package/dist/types/schemas/discussion.js.map +1 -0
- package/dist/types/schemas/entitlements.d.ts +50 -0
- package/dist/types/schemas/entitlements.js +38 -0
- package/dist/types/schemas/entitlements.js.map +1 -0
- package/dist/types/schemas/identity.d.ts +37 -0
- package/dist/types/schemas/identity.js +34 -0
- package/dist/types/schemas/identity.js.map +1 -0
- package/dist/types/schemas/index.d.ts +14 -0
- package/dist/types/schemas/index.js +14 -0
- package/dist/types/schemas/integrations.d.ts +36 -0
- package/dist/types/schemas/integrations.js +30 -0
- package/dist/types/schemas/integrations.js.map +1 -0
- package/dist/types/schemas/organizations.d.ts +135 -0
- package/dist/types/schemas/organizations.js +90 -0
- package/dist/types/schemas/organizations.js.map +1 -0
- package/dist/types/schemas/outbox.d.ts +19 -0
- package/dist/types/schemas/outbox.js +18 -0
- package/dist/types/schemas/outbox.js.map +1 -0
- package/dist/types/schemas/progress.d.ts +53 -0
- package/dist/types/schemas/progress.js +37 -0
- package/dist/types/schemas/progress.js.map +1 -0
- package/dist/types/schemas/settings.d.ts +16 -0
- package/dist/types/schemas/settings.js +15 -0
- package/dist/types/schemas/settings.js.map +1 -0
- package/dist/types/schemas/shared.d.ts +13 -0
- package/dist/types/schemas/shared.js +28 -0
- package/dist/types/schemas/shared.js.map +1 -0
- package/dist/types/shared.d.ts +25 -0
- package/dist/types/shared.js +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { noopLogger } from "../shared/logger.js";
|
|
2
|
+
import { entitlementEvents } from "./events.js";
|
|
3
|
+
//#region src/entitlements/service.ts
|
|
4
|
+
var EntitlementsServiceImpl = class {
|
|
5
|
+
repo;
|
|
6
|
+
uow;
|
|
7
|
+
logger;
|
|
8
|
+
constructor(params) {
|
|
9
|
+
this.repo = params.repo;
|
|
10
|
+
this.uow = params.uow;
|
|
11
|
+
this.logger = params.logger ?? noopLogger;
|
|
12
|
+
}
|
|
13
|
+
list(orgId, query) {
|
|
14
|
+
return this.repo.list(orgId, query);
|
|
15
|
+
}
|
|
16
|
+
async grant(orgId, input) {
|
|
17
|
+
const entitlement = await this.uow.run(async ({ entitlements, outbox }) => {
|
|
18
|
+
const created = await entitlements.insert(orgId, input);
|
|
19
|
+
await outbox.append([entitlementEvents.entitlementCreated.make({
|
|
20
|
+
orgId,
|
|
21
|
+
data: created
|
|
22
|
+
})]);
|
|
23
|
+
return created;
|
|
24
|
+
});
|
|
25
|
+
this.logger.info("entitlement granted", {
|
|
26
|
+
orgId,
|
|
27
|
+
entitlementId: entitlement.id,
|
|
28
|
+
orgUserId: entitlement.orgUserId,
|
|
29
|
+
contentId: entitlement.contentId
|
|
30
|
+
});
|
|
31
|
+
return entitlement;
|
|
32
|
+
}
|
|
33
|
+
async setStatus(orgId, id, status) {
|
|
34
|
+
const entitlement = await this.uow.run(async ({ entitlements, outbox }) => {
|
|
35
|
+
const updated = await entitlements.setStatus(orgId, id, status);
|
|
36
|
+
if (!updated) return null;
|
|
37
|
+
await outbox.append([status === "revoked" ? entitlementEvents.entitlementDeleted.make({
|
|
38
|
+
orgId,
|
|
39
|
+
data: updated
|
|
40
|
+
}) : entitlementEvents.entitlementUpdated.make({
|
|
41
|
+
orgId,
|
|
42
|
+
data: updated
|
|
43
|
+
})]);
|
|
44
|
+
return updated;
|
|
45
|
+
});
|
|
46
|
+
if (entitlement) this.logger.info("entitlement status changed", {
|
|
47
|
+
orgId,
|
|
48
|
+
entitlementId: id,
|
|
49
|
+
status
|
|
50
|
+
});
|
|
51
|
+
return entitlement;
|
|
52
|
+
}
|
|
53
|
+
hasCourseAccess(orgId, orgUserId, courseId) {
|
|
54
|
+
return this.repo.hasCourseAccess(orgId, orgUserId, courseId);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { EntitlementsServiceImpl };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../src/entitlements/service.ts"],"sourcesContent":["// entitlements context — service implementation (inbound port).\n//\n// Mutations run inside the context's UnitOfWork: the domain write and the\n// outbox append commit in ONE transaction (transactional outbox). This\n// service never publishes — the outbox relay republishes committed events to\n// the EventBus at-least-once.\nimport type { Entitlement, EntitlementsQuery, GrantEntitlementInput, Page } from './model.js';\nimport type {\n EntitlementsRepository,\n EntitlementsService,\n EntitlementsUnitOfWork,\n} from './ports.js';\nimport type { Logger } from '../shared/ports.js';\nimport { noopLogger } from '../shared/logger.js';\nimport { entitlementEvents } from './events.js';\n\nexport type EntitlementsServiceParams = {\n /** Read-only access (list) — runs outside any transaction. */\n repo: EntitlementsRepository;\n /** Atomic write scope: tx-bound repo + outbox appender. */\n uow: EntitlementsUnitOfWork;\n logger?: Logger;\n};\n\nexport class EntitlementsServiceImpl implements EntitlementsService {\n private readonly repo: EntitlementsRepository;\n private readonly uow: EntitlementsUnitOfWork;\n private readonly logger: Logger;\n\n constructor(params: EntitlementsServiceParams) {\n this.repo = params.repo;\n this.uow = params.uow;\n this.logger = params.logger ?? noopLogger;\n }\n\n list(orgId: string, query: EntitlementsQuery): Promise<Page<Entitlement>> {\n return this.repo.list(orgId, query);\n }\n\n async grant(orgId: string, input: GrantEntitlementInput): Promise<Entitlement> {\n const entitlement = await this.uow.run(async ({ entitlements, outbox }) => {\n const created = await entitlements.insert(orgId, input);\n await outbox.append([\n entitlementEvents.entitlementCreated.make({\n orgId,\n data: created,\n }),\n ]);\n return created;\n });\n this.logger.info('entitlement granted', {\n orgId,\n entitlementId: entitlement.id,\n orgUserId: entitlement.orgUserId,\n contentId: entitlement.contentId,\n });\n return entitlement;\n }\n\n async setStatus(\n orgId: string,\n id: string,\n status: 'active' | 'revoked',\n ): Promise<Entitlement | null> {\n const entitlement = await this.uow.run(async ({ entitlements, outbox }) => {\n const updated = await entitlements.setStatus(orgId, id, status);\n if (!updated) {\n return null;\n }\n await outbox.append([\n status === 'revoked'\n ? entitlementEvents.entitlementDeleted.make({\n orgId,\n data: updated,\n })\n : entitlementEvents.entitlementUpdated.make({\n orgId,\n data: updated,\n }),\n ]);\n return updated;\n });\n if (entitlement) {\n this.logger.info('entitlement status changed', { orgId, entitlementId: id, status });\n }\n return entitlement;\n }\n\n hasCourseAccess(orgId: string, orgUserId: string, courseId: string): Promise<boolean> {\n return this.repo.hasCourseAccess(orgId, orgUserId, courseId);\n }\n}\n"],"mappings":";;;AAwBA,IAAa,0BAAb,MAAoE;CAClE;CACA;CACA;CAEA,YAAY,QAAmC;EAC7C,KAAK,OAAO,OAAO;EACnB,KAAK,MAAM,OAAO;EAClB,KAAK,SAAS,OAAO,UAAU;CACjC;CAEA,KAAK,OAAe,OAAsD;EACxE,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK;CACpC;CAEA,MAAM,MAAM,OAAe,OAAoD;EAC7E,MAAM,cAAc,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,cAAc,aAAa;GACzE,MAAM,UAAU,MAAM,aAAa,OAAO,OAAO,KAAK;GACtD,MAAM,OAAO,OAAO,CAClB,kBAAkB,mBAAmB,KAAK;IACxC;IACA,MAAM;GACR,CAAC,CACH,CAAC;GACD,OAAO;EACT,CAAC;EACD,KAAK,OAAO,KAAK,uBAAuB;GACtC;GACA,eAAe,YAAY;GAC3B,WAAW,YAAY;GACvB,WAAW,YAAY;EACzB,CAAC;EACD,OAAO;CACT;CAEA,MAAM,UACJ,OACA,IACA,QAC6B;EAC7B,MAAM,cAAc,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,cAAc,aAAa;GACzE,MAAM,UAAU,MAAM,aAAa,UAAU,OAAO,IAAI,MAAM;GAC9D,IAAI,CAAC,SACH,OAAO;GAET,MAAM,OAAO,OAAO,CAClB,WAAW,YACP,kBAAkB,mBAAmB,KAAK;IACxC;IACA,MAAM;GACR,CAAC,IACD,kBAAkB,mBAAmB,KAAK;IACxC;IACA,MAAM;GACR,CAAC,CACP,CAAC;GACD,OAAO;EACT,CAAC;EACD,IAAI,aACF,KAAK,OAAO,KAAK,8BAA8B;GAAE;GAAO,eAAe;GAAI;EAAO,CAAC;EAErF,OAAO;CACT;CAEA,gBAAgB,OAAe,WAAmB,UAAoC;EACpF,OAAO,KAAK,KAAK,gBAAgB,OAAO,WAAW,QAAQ;CAC7D;AACF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { EventOf, EventOfValues, RuntimeEventDefinition, VersionedDomainEvent } from "../shared/events.js";
|
|
2
|
+
import "../shared/ports.js";
|
|
3
|
+
//#region src/identity/events.d.ts
|
|
4
|
+
declare const identityEvents: {
|
|
5
|
+
userCreated: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
6
|
+
id: string;
|
|
7
|
+
externalId: string | null;
|
|
8
|
+
email: string;
|
|
9
|
+
firstName: string | null;
|
|
10
|
+
lastName: string | null;
|
|
11
|
+
createdAt: Date;
|
|
12
|
+
updatedAt: Date;
|
|
13
|
+
}, "identity.user.created", 1>, {
|
|
14
|
+
id: string;
|
|
15
|
+
externalId: string | null;
|
|
16
|
+
email: string;
|
|
17
|
+
firstName: string | null;
|
|
18
|
+
lastName: string | null;
|
|
19
|
+
createdAt: unknown;
|
|
20
|
+
updatedAt: unknown;
|
|
21
|
+
}>;
|
|
22
|
+
userUpdated: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
23
|
+
id: string;
|
|
24
|
+
externalId: string | null;
|
|
25
|
+
email: string;
|
|
26
|
+
firstName: string | null;
|
|
27
|
+
lastName: string | null;
|
|
28
|
+
createdAt: Date;
|
|
29
|
+
updatedAt: Date;
|
|
30
|
+
}, "identity.user.updated", 1>, {
|
|
31
|
+
id: string;
|
|
32
|
+
externalId: string | null;
|
|
33
|
+
email: string;
|
|
34
|
+
firstName: string | null;
|
|
35
|
+
lastName: string | null;
|
|
36
|
+
createdAt: unknown;
|
|
37
|
+
updatedAt: unknown;
|
|
38
|
+
}>;
|
|
39
|
+
userDeleted: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
40
|
+
id: string;
|
|
41
|
+
externalId: string | null;
|
|
42
|
+
email: string;
|
|
43
|
+
firstName: string | null;
|
|
44
|
+
lastName: string | null;
|
|
45
|
+
createdAt: Date;
|
|
46
|
+
updatedAt: Date;
|
|
47
|
+
}, "identity.user.deleted", 1>, {
|
|
48
|
+
id: string;
|
|
49
|
+
externalId: string | null;
|
|
50
|
+
email: string;
|
|
51
|
+
firstName: string | null;
|
|
52
|
+
lastName: string | null;
|
|
53
|
+
createdAt: unknown;
|
|
54
|
+
updatedAt: unknown;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
type UserCreated = EventOf<typeof identityEvents.userCreated>;
|
|
58
|
+
type UserUpdated = EventOf<typeof identityEvents.userUpdated>;
|
|
59
|
+
type UserDeleted = EventOf<typeof identityEvents.userDeleted>;
|
|
60
|
+
type IdentityEvent = EventOfValues<typeof identityEvents>;
|
|
61
|
+
//#endregion
|
|
62
|
+
export { IdentityEvent, UserCreated, UserDeleted, UserUpdated, identityEvents };
|
|
63
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { userSchema } from "../types/schemas/identity.js";
|
|
2
|
+
import { defineEvent } from "../shared/events.js";
|
|
3
|
+
//#region src/identity/events.ts
|
|
4
|
+
const identityEvents = {
|
|
5
|
+
userCreated: defineEvent({
|
|
6
|
+
type: "identity.user.created",
|
|
7
|
+
version: 1,
|
|
8
|
+
data: userSchema
|
|
9
|
+
}),
|
|
10
|
+
userUpdated: defineEvent({
|
|
11
|
+
type: "identity.user.updated",
|
|
12
|
+
version: 1,
|
|
13
|
+
data: userSchema
|
|
14
|
+
}),
|
|
15
|
+
userDeleted: defineEvent({
|
|
16
|
+
type: "identity.user.deleted",
|
|
17
|
+
version: 1,
|
|
18
|
+
data: userSchema
|
|
19
|
+
})
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { identityEvents };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../src/identity/events.ts"],"sourcesContent":["import { userSchema } from '../types/schemas/index.js';\nimport { defineEvent, type EventOf, type EventOfValues } from '../shared/ports.js';\n\nexport const identityEvents = {\n userCreated: defineEvent({\n type: 'identity.user.created',\n version: 1,\n data: userSchema,\n }),\n userUpdated: defineEvent({\n type: 'identity.user.updated',\n version: 1,\n data: userSchema,\n }),\n userDeleted: defineEvent({\n type: 'identity.user.deleted',\n version: 1,\n data: userSchema,\n }),\n};\n\nexport type UserCreated = EventOf<typeof identityEvents.userCreated>;\nexport type UserUpdated = EventOf<typeof identityEvents.userUpdated>;\nexport type UserDeleted = EventOf<typeof identityEvents.userDeleted>;\nexport type IdentityEvent = EventOfValues<typeof identityEvents>;\n"],"mappings":";;;AAGA,MAAa,iBAAiB;CAC5B,aAAa,YAAY;EACvB,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;CACD,aAAa,YAAY;EACvB,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;CACD,aAAa,YAAY;EACvB,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;AACH"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CreateUserInput, ProvisionUserInput, UpdateUserInput } from "../types/schemas/identity.js";
|
|
2
|
+
import { User, UserId } from "../types/identity.js";
|
|
3
|
+
import { IdentityEvent, UserCreated, UserDeleted, UserUpdated, identityEvents } from "./events.js";
|
|
4
|
+
import "./model.js";
|
|
5
|
+
import "./types.js";
|
|
6
|
+
import { AuthHeaders, IdentityRepository, IdentityService, SessionAdmin, UserEditor, UserProvisioner, UserResolver } from "./ports.js";
|
|
7
|
+
import { IdentityServiceImpl } from "./service.js";
|
|
8
|
+
export { type AuthHeaders, type CreateUserInput, type IdentityEvent, type IdentityRepository, type IdentityService, IdentityServiceImpl, type ProvisionUserInput, type SessionAdmin, type UpdateUserInput, type User, type UserCreated, type UserDeleted, type UserEditor, type UserId, type UserProvisioner, type UserResolver, type UserUpdated, identityEvents };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CreateUserInput, UpdateUserInput } from "../types/schemas/identity.js";
|
|
2
|
+
import { User } from "../types/identity.js";
|
|
3
|
+
import { OutboxAppender, UnitOfWork } from "../shared/ports.js";
|
|
4
|
+
import "./model.js";
|
|
5
|
+
import "./types.js";
|
|
6
|
+
//#region src/identity/ports.d.ts
|
|
7
|
+
interface UserProvisioner {
|
|
8
|
+
createUser(input: CreateUserInput): Promise<User>;
|
|
9
|
+
/** Auth signup entry point. Claims a person provisioned at invite time by
|
|
10
|
+
* stamping `externalId`; creates the person when the email is unknown.
|
|
11
|
+
* Throws ConflictError when the email is already linked to an account. */
|
|
12
|
+
linkOrCreateUser(input: CreateUserInput): Promise<User>;
|
|
13
|
+
sendPasswordReset(input: {
|
|
14
|
+
email: string;
|
|
15
|
+
url: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
sendMagicLink(input: {
|
|
18
|
+
email: string;
|
|
19
|
+
url: string;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/** Resolves an auth account to the domain person. Used by the organizations
|
|
23
|
+
* context at invite acceptance, so core never reads the auth schema. */
|
|
24
|
+
interface UserResolver {
|
|
25
|
+
getUserByExternalId(externalId: string): Promise<User | null>;
|
|
26
|
+
/** A hit says a person exists, NOT that they can sign in — provisioned
|
|
27
|
+
* students have no account until `externalId` is filled in. */
|
|
28
|
+
getUserByEmail(email: string): Promise<User | null>;
|
|
29
|
+
getUserById(id: string): Promise<User | null>;
|
|
30
|
+
}
|
|
31
|
+
/** Corrects the person an admin named. Throws ConflictError when a new address
|
|
32
|
+
* already belongs to somebody else. */
|
|
33
|
+
interface UserEditor {
|
|
34
|
+
updateUser(id: string, input: UpdateUserInput): Promise<User>;
|
|
35
|
+
}
|
|
36
|
+
/** Inbound HTTP headers carrying the session, forwarded to the auth provider. */
|
|
37
|
+
type AuthHeaders = Record<string, string | string[] | undefined>;
|
|
38
|
+
/** Writes to a live session, fulfilled by the auth provider. */
|
|
39
|
+
interface SessionAdmin {
|
|
40
|
+
/** Points the caller's current session at `orgId`. */
|
|
41
|
+
stampActiveOrganization(headers: AuthHeaders, orgId: string): Promise<boolean>;
|
|
42
|
+
}
|
|
43
|
+
interface IdentityService extends UserProvisioner, UserResolver, UserEditor {}
|
|
44
|
+
interface IdentityRepository {
|
|
45
|
+
insertUser(input: CreateUserInput): Promise<User>;
|
|
46
|
+
updateUser(id: string, input: UpdateUserInput): Promise<User | null>;
|
|
47
|
+
findUserById(id: string): Promise<User | null>;
|
|
48
|
+
findUserByExternalId(externalId: string): Promise<User | null>;
|
|
49
|
+
findUserByEmail(email: string): Promise<User | null>;
|
|
50
|
+
}
|
|
51
|
+
interface IdentityTxScope {
|
|
52
|
+
identity: IdentityRepository;
|
|
53
|
+
outbox: OutboxAppender;
|
|
54
|
+
}
|
|
55
|
+
type IdentityUnitOfWork = UnitOfWork<IdentityTxScope>;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { AuthHeaders, IdentityRepository, IdentityService, IdentityTxScope, IdentityUnitOfWork, SessionAdmin, UserEditor, UserProvisioner, UserResolver };
|
|
58
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Logger } from "../types/ports.js";
|
|
2
|
+
import { CreateUserInput, UpdateUserInput } from "../types/schemas/identity.js";
|
|
3
|
+
import { User } from "../types/identity.js";
|
|
4
|
+
import "../shared/ports.js";
|
|
5
|
+
import { Mailer } from "../shared/mailer.js";
|
|
6
|
+
import "./model.js";
|
|
7
|
+
import "./types.js";
|
|
8
|
+
import { IdentityRepository, IdentityService, IdentityUnitOfWork } from "./ports.js";
|
|
9
|
+
//#region src/identity/service.d.ts
|
|
10
|
+
declare class IdentityServiceImpl implements IdentityService {
|
|
11
|
+
private readonly repo;
|
|
12
|
+
private readonly logger;
|
|
13
|
+
private readonly uow;
|
|
14
|
+
private readonly mailer;
|
|
15
|
+
constructor(input: {
|
|
16
|
+
repo: IdentityRepository;
|
|
17
|
+
logger?: Logger;
|
|
18
|
+
mailer: Mailer;
|
|
19
|
+
uow: IdentityUnitOfWork;
|
|
20
|
+
});
|
|
21
|
+
createUser(input: CreateUserInput): Promise<User>;
|
|
22
|
+
linkOrCreateUser(input: CreateUserInput): Promise<User>;
|
|
23
|
+
updateUser(id: string, input: UpdateUserInput): Promise<User>;
|
|
24
|
+
getUserByExternalId(externalId: string): Promise<User | null>;
|
|
25
|
+
getUserByEmail(email: string): Promise<User | null>;
|
|
26
|
+
getUserById(id: string): Promise<User | null>;
|
|
27
|
+
sendPasswordReset(input: {
|
|
28
|
+
email: string;
|
|
29
|
+
url: string;
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
sendMagicLink(input: {
|
|
32
|
+
email: string;
|
|
33
|
+
url: string;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { IdentityServiceImpl };
|
|
38
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { noopLogger } from "../shared/logger.js";
|
|
2
|
+
import { ConflictError, NotFoundError } from "../shared/errors.js";
|
|
3
|
+
import { identityEvents } from "./events.js";
|
|
4
|
+
//#region src/identity/service.ts
|
|
5
|
+
var IdentityServiceImpl = class {
|
|
6
|
+
repo;
|
|
7
|
+
logger;
|
|
8
|
+
uow;
|
|
9
|
+
mailer;
|
|
10
|
+
constructor(input) {
|
|
11
|
+
this.repo = input.repo;
|
|
12
|
+
this.mailer = input.mailer;
|
|
13
|
+
this.logger = input.logger ?? noopLogger;
|
|
14
|
+
this.uow = input.uow;
|
|
15
|
+
}
|
|
16
|
+
async createUser(input) {
|
|
17
|
+
const created = await this.uow.run(async ({ identity, outbox }) => {
|
|
18
|
+
const user = await identity.insertUser(input);
|
|
19
|
+
await outbox.append([identityEvents.userCreated.make({
|
|
20
|
+
orgId: "-",
|
|
21
|
+
data: user
|
|
22
|
+
})]);
|
|
23
|
+
return user;
|
|
24
|
+
});
|
|
25
|
+
this.logger.info("user created", { user: created });
|
|
26
|
+
return created;
|
|
27
|
+
}
|
|
28
|
+
async linkOrCreateUser(input) {
|
|
29
|
+
const existing = await this.repo.findUserByEmail(input.email);
|
|
30
|
+
if (!existing) return this.createUser(input);
|
|
31
|
+
if (existing.externalId !== null) throw new ConflictError("That email already has an account");
|
|
32
|
+
const linked = await this.uow.run(async ({ identity, outbox }) => {
|
|
33
|
+
const user = await identity.updateUser(existing.id, {
|
|
34
|
+
externalId: existing.id,
|
|
35
|
+
...input.firstName !== void 0 && { firstName: input.firstName },
|
|
36
|
+
...input.lastName !== void 0 && { lastName: input.lastName }
|
|
37
|
+
});
|
|
38
|
+
await outbox.append([identityEvents.userUpdated.make({
|
|
39
|
+
orgId: "-",
|
|
40
|
+
data: user
|
|
41
|
+
})]);
|
|
42
|
+
return user;
|
|
43
|
+
});
|
|
44
|
+
this.logger.info("user linked to auth account", { user: linked });
|
|
45
|
+
return linked;
|
|
46
|
+
}
|
|
47
|
+
async updateUser(id, input) {
|
|
48
|
+
if (!await this.repo.findUserById(id)) throw new NotFoundError("User", id);
|
|
49
|
+
const updated = await this.uow.run(async ({ identity, outbox }) => {
|
|
50
|
+
const user = await identity.updateUser(id, input);
|
|
51
|
+
await outbox.append([identityEvents.userUpdated.make({
|
|
52
|
+
orgId: "-",
|
|
53
|
+
data: user
|
|
54
|
+
})]);
|
|
55
|
+
return user;
|
|
56
|
+
});
|
|
57
|
+
this.logger.info("user updated", { user: updated });
|
|
58
|
+
return updated;
|
|
59
|
+
}
|
|
60
|
+
async getUserByExternalId(externalId) {
|
|
61
|
+
return this.repo.findUserByExternalId(externalId);
|
|
62
|
+
}
|
|
63
|
+
async getUserByEmail(email) {
|
|
64
|
+
return this.repo.findUserByEmail(email);
|
|
65
|
+
}
|
|
66
|
+
async getUserById(id) {
|
|
67
|
+
return this.repo.findUserById(id);
|
|
68
|
+
}
|
|
69
|
+
async sendPasswordReset(input) {
|
|
70
|
+
await this.mailer.send(input.email, "passwordReset", { resetUrl: input.url });
|
|
71
|
+
}
|
|
72
|
+
async sendMagicLink(input) {
|
|
73
|
+
await this.mailer.send(input.email, "magicLink", { url: input.url });
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { IdentityServiceImpl };
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../src/identity/service.ts"],"sourcesContent":["import type { IdentityRepository, IdentityService, IdentityUnitOfWork } from './ports.js';\nimport type { User } from './model.js';\nimport type { CreateUserInput, UpdateUserInput } from './types.js';\nimport type { Logger } from '../shared/ports.js';\nimport { noopLogger } from '../shared/logger.js';\nimport { ConflictError, NotFoundError } from '../shared/errors.js';\nimport type { Mailer } from '../shared/mailer.js';\nimport { identityEvents } from './events.js';\n\nexport class IdentityServiceImpl implements IdentityService {\n private readonly repo: IdentityRepository;\n private readonly logger: Logger;\n private readonly uow: IdentityUnitOfWork;\n private readonly mailer: Pick<Mailer, 'send'>;\n\n constructor(input: {\n repo: IdentityRepository;\n logger?: Logger;\n mailer: Mailer;\n uow: IdentityUnitOfWork;\n }) {\n this.repo = input.repo;\n this.mailer = input.mailer;\n this.logger = input.logger ?? noopLogger;\n this.uow = input.uow;\n }\n\n async createUser(input: CreateUserInput): Promise<User> {\n const created = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.insertUser(input);\n await outbox.append([\n identityEvents.userCreated.make({ orgId: '-', data: user }),\n ]);\n return user;\n });\n this.logger.info('user created', { user: created });\n return created;\n }\n\n async linkOrCreateUser(input: CreateUserInput): Promise<User> {\n const existing = await this.repo.findUserByEmail(input.email);\n if (!existing) {\n return this.createUser(input);\n }\n if (existing.externalId !== null) {\n throw new ConflictError('That email already has an account');\n }\n // Existing user without external link, so invited. update the user with the\n // id.\n const linked = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.updateUser(existing.id, {\n externalId: existing.id,\n ...(input.firstName !== undefined && { firstName: input.firstName }),\n ...(input.lastName !== undefined && { lastName: input.lastName }),\n });\n await outbox.append([\n identityEvents.userUpdated.make({ orgId: '-', data: user! }),\n ]);\n return user!;\n });\n this.logger.info('user linked to auth account', { user: linked });\n return linked;\n }\n\n async updateUser(id: string, input: UpdateUserInput): Promise<User> {\n const person = await this.repo.findUserById(id);\n if (!person) {\n throw new NotFoundError('User', id);\n }\n\n const updated = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.updateUser(id, input);\n await outbox.append([\n identityEvents.userUpdated.make({ orgId: '-', data: user! }),\n ]);\n return user!;\n });\n this.logger.info('user updated', { user: updated });\n return updated;\n }\n\n async getUserByExternalId(externalId: string): Promise<User | null> {\n return this.repo.findUserByExternalId(externalId);\n }\n\n async getUserByEmail(email: string): Promise<User | null> {\n return this.repo.findUserByEmail(email);\n }\n\n async getUserById(id: string): Promise<User | null> {\n return this.repo.findUserById(id);\n }\n\n async sendPasswordReset(input: { email: string; url: string }): Promise<void> {\n await this.mailer.send(input.email, 'passwordReset', { resetUrl: input.url });\n }\n\n async sendMagicLink(input: { email: string; url: string }): Promise<void> {\n await this.mailer.send(input.email, 'magicLink', { url: input.url });\n }\n}\n"],"mappings":";;;;AASA,IAAa,sBAAb,MAA4D;CAC1D;CACA;CACA;CACA;CAEA,YAAY,OAKT;EACD,KAAK,OAAO,MAAM;EAClB,KAAK,SAAS,MAAM;EACpB,KAAK,SAAS,MAAM,UAAU;EAC9B,KAAK,MAAM,MAAM;CACnB;CAEA,MAAM,WAAW,OAAuC;EACtD,MAAM,UAAU,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,UAAU,aAAa;GACjE,MAAM,OAAO,MAAM,SAAS,WAAW,KAAK;GAC5C,MAAM,OAAO,OAAO,CAClB,eAAe,YAAY,KAAK;IAAE,OAAO;IAAK,MAAM;GAAK,CAAC,CAC5D,CAAC;GACD,OAAO;EACT,CAAC;EACD,KAAK,OAAO,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;EAClD,OAAO;CACT;CAEA,MAAM,iBAAiB,OAAuC;EAC5D,MAAM,WAAW,MAAM,KAAK,KAAK,gBAAgB,MAAM,KAAK;EAC5D,IAAI,CAAC,UACH,OAAO,KAAK,WAAW,KAAK;EAE9B,IAAI,SAAS,eAAe,MAC1B,MAAM,IAAI,cAAc,mCAAmC;EAI7D,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,UAAU,aAAa;GAChE,MAAM,OAAO,MAAM,SAAS,WAAW,SAAS,IAAI;IAClD,YAAY,SAAS;IACrB,GAAI,MAAM,cAAc,KAAA,KAAa,EAAE,WAAW,MAAM,UAAU;IAClE,GAAI,MAAM,aAAa,KAAA,KAAa,EAAE,UAAU,MAAM,SAAS;GACjE,CAAC;GACD,MAAM,OAAO,OAAO,CAClB,eAAe,YAAY,KAAK;IAAE,OAAO;IAAK,MAAM;GAAM,CAAC,CAC7D,CAAC;GACD,OAAO;EACT,CAAC;EACD,KAAK,OAAO,KAAK,+BAA+B,EAAE,MAAM,OAAO,CAAC;EAChE,OAAO;CACT;CAEA,MAAM,WAAW,IAAY,OAAuC;EAElE,IAAI,CAAC,MADgB,KAAK,KAAK,aAAa,EAAE,GAE5C,MAAM,IAAI,cAAc,QAAQ,EAAE;EAGpC,MAAM,UAAU,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,UAAU,aAAa;GACjE,MAAM,OAAO,MAAM,SAAS,WAAW,IAAI,KAAK;GAChD,MAAM,OAAO,OAAO,CAClB,eAAe,YAAY,KAAK;IAAE,OAAO;IAAK,MAAM;GAAM,CAAC,CAC7D,CAAC;GACD,OAAO;EACT,CAAC;EACD,KAAK,OAAO,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;EAClD,OAAO;CACT;CAEA,MAAM,oBAAoB,YAA0C;EAClE,OAAO,KAAK,KAAK,qBAAqB,UAAU;CAClD;CAEA,MAAM,eAAe,OAAqC;EACxD,OAAO,KAAK,KAAK,gBAAgB,KAAK;CACxC;CAEA,MAAM,YAAY,IAAkC;EAClD,OAAO,KAAK,KAAK,aAAa,EAAE;CAClC;CAEA,MAAM,kBAAkB,OAAsD;EAC5E,MAAM,KAAK,OAAO,KAAK,MAAM,OAAO,iBAAiB,EAAE,UAAU,MAAM,IAAI,CAAC;CAC9E;CAEA,MAAM,cAAc,OAAsD;EACxE,MAAM,KAAK,OAAO,KAAK,MAAM,OAAO,aAAa,EAAE,KAAK,MAAM,IAAI,CAAC;CACrE;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { JsonValue } from "../types/shared.js";
|
|
2
|
+
import { EventOf, EventOfValues, RuntimeEventDefinition, VersionedDomainEvent } from "../shared/events.js";
|
|
3
|
+
import "../shared/ports.js";
|
|
4
|
+
//#region src/integrations/events.d.ts
|
|
5
|
+
declare const integrationEvents: {
|
|
6
|
+
connectionCreated: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
7
|
+
orgId: string;
|
|
8
|
+
id: string;
|
|
9
|
+
integrationId: string;
|
|
10
|
+
config: Record<string, JsonValue>;
|
|
11
|
+
active: boolean;
|
|
12
|
+
credentialRef: string;
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
updatedAt: Date;
|
|
15
|
+
}, "integration.connection.created", 1>, {
|
|
16
|
+
orgId: string;
|
|
17
|
+
id: string;
|
|
18
|
+
integrationId: string;
|
|
19
|
+
config: Record<string, unknown>;
|
|
20
|
+
active: boolean;
|
|
21
|
+
credentialRef: string;
|
|
22
|
+
createdAt: unknown;
|
|
23
|
+
updatedAt: unknown;
|
|
24
|
+
}>;
|
|
25
|
+
connectionUpdated: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
26
|
+
orgId: string;
|
|
27
|
+
id: string;
|
|
28
|
+
integrationId: string;
|
|
29
|
+
config: Record<string, JsonValue>;
|
|
30
|
+
active: boolean;
|
|
31
|
+
credentialRef: string;
|
|
32
|
+
createdAt: Date;
|
|
33
|
+
updatedAt: Date;
|
|
34
|
+
}, "integration.connection.updated", 1>, {
|
|
35
|
+
orgId: string;
|
|
36
|
+
id: string;
|
|
37
|
+
integrationId: string;
|
|
38
|
+
config: Record<string, unknown>;
|
|
39
|
+
active: boolean;
|
|
40
|
+
credentialRef: string;
|
|
41
|
+
createdAt: unknown;
|
|
42
|
+
updatedAt: unknown;
|
|
43
|
+
}>;
|
|
44
|
+
connectionRemoved: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
45
|
+
orgId: string;
|
|
46
|
+
id: string;
|
|
47
|
+
integrationId: string;
|
|
48
|
+
config: Record<string, JsonValue>;
|
|
49
|
+
active: boolean;
|
|
50
|
+
credentialRef: string;
|
|
51
|
+
createdAt: Date;
|
|
52
|
+
updatedAt: Date;
|
|
53
|
+
}, "integration.connection.removed", 1>, {
|
|
54
|
+
orgId: string;
|
|
55
|
+
id: string;
|
|
56
|
+
integrationId: string;
|
|
57
|
+
config: Record<string, unknown>;
|
|
58
|
+
active: boolean;
|
|
59
|
+
credentialRef: string;
|
|
60
|
+
createdAt: unknown;
|
|
61
|
+
updatedAt: unknown;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
type ConnectionCreated = EventOf<typeof integrationEvents.connectionCreated>;
|
|
65
|
+
type ConnectionUpdated = EventOf<typeof integrationEvents.connectionUpdated>;
|
|
66
|
+
type ConnectionRemoved = EventOf<typeof integrationEvents.connectionRemoved>;
|
|
67
|
+
type IntegrationEvent = EventOfValues<typeof integrationEvents>;
|
|
68
|
+
//#endregion
|
|
69
|
+
export { ConnectionCreated, ConnectionRemoved, ConnectionUpdated, IntegrationEvent, integrationEvents };
|
|
70
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { connectionSchema } from "../types/schemas/integrations.js";
|
|
2
|
+
import { defineEvent } from "../shared/events.js";
|
|
3
|
+
//#region src/integrations/events.ts
|
|
4
|
+
const integrationEvents = {
|
|
5
|
+
connectionCreated: defineEvent({
|
|
6
|
+
type: "integration.connection.created",
|
|
7
|
+
version: 1,
|
|
8
|
+
data: connectionSchema
|
|
9
|
+
}),
|
|
10
|
+
connectionUpdated: defineEvent({
|
|
11
|
+
type: "integration.connection.updated",
|
|
12
|
+
version: 1,
|
|
13
|
+
data: connectionSchema
|
|
14
|
+
}),
|
|
15
|
+
connectionRemoved: defineEvent({
|
|
16
|
+
type: "integration.connection.removed",
|
|
17
|
+
version: 1,
|
|
18
|
+
data: connectionSchema
|
|
19
|
+
})
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { integrationEvents };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../src/integrations/events.ts"],"sourcesContent":["import { connectionSchema } from '../types/schemas/index.js';\nimport { defineEvent, type EventOf, type EventOfValues } from '../shared/ports.js';\n\nexport const integrationEvents = {\n connectionCreated: defineEvent({\n type: 'integration.connection.created',\n version: 1,\n data: connectionSchema,\n }),\n connectionUpdated: defineEvent({\n type: 'integration.connection.updated',\n version: 1,\n data: connectionSchema,\n }),\n connectionRemoved: defineEvent({\n type: 'integration.connection.removed',\n version: 1,\n data: connectionSchema,\n }),\n};\n\nexport type ConnectionCreated = EventOf<typeof integrationEvents.connectionCreated>;\nexport type ConnectionUpdated = EventOf<typeof integrationEvents.connectionUpdated>;\nexport type ConnectionRemoved = EventOf<typeof integrationEvents.connectionRemoved>;\nexport type IntegrationEvent = EventOfValues<typeof integrationEvents>;\n"],"mappings":";;;AAGA,MAAa,oBAAoB;CAC/B,mBAAmB,YAAY;EAC7B,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;CACD,mBAAmB,YAAY;EAC7B,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;CACD,mBAAmB,YAAY;EAC7B,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;AACH"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ConfigureInput, ConnectInput, Connection, Validation } from "../types/schemas/integrations.js";
|
|
2
|
+
import { Action, ActionContext, Integration } from "../types/integrations.js";
|
|
3
|
+
import { ActionInvocationError, AlreadyConnectedError, InvalidConfigError, UnknownIntegrationError } from "./model.js";
|
|
4
|
+
import { AvailableIntegration, ConnectionsRepository, IntegrationsRegistry, IntegrationsService } from "./ports.js";
|
|
5
|
+
import { IntegrationsServiceImpl } from "./service.js";
|
|
6
|
+
import { ConnectionCreated, ConnectionRemoved, ConnectionUpdated, integrationEvents } from "./events.js";
|
|
7
|
+
import { createIntegrationsRegistry } from "./registry.js";
|
|
8
|
+
import { zodAction, zodConfig, zodSecrets } from "./zod.js";
|
|
9
|
+
export { type Action, type ActionContext, ActionInvocationError, AlreadyConnectedError, type AvailableIntegration, type ConfigureInput, type ConnectInput, type Connection, type ConnectionCreated, type ConnectionRemoved, type ConnectionUpdated, type ConnectionsRepository, type Integration, type IntegrationsRegistry, type IntegrationsService, IntegrationsServiceImpl, InvalidConfigError, UnknownIntegrationError, type Validation, createIntegrationsRegistry, integrationEvents, zodAction, zodConfig, zodSecrets };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ActionInvocationError, AlreadyConnectedError, InvalidConfigError, UnknownIntegrationError } from "./model.js";
|
|
2
|
+
import { integrationEvents } from "./events.js";
|
|
3
|
+
import { IntegrationsServiceImpl } from "./service.js";
|
|
4
|
+
import { createIntegrationsRegistry } from "./registry.js";
|
|
5
|
+
import { zodAction, zodConfig, zodSecrets } from "./zod.js";
|
|
6
|
+
export { ActionInvocationError, AlreadyConnectedError, IntegrationsServiceImpl, InvalidConfigError, UnknownIntegrationError, createIntegrationsRegistry, integrationEvents, zodAction, zodConfig, zodSecrets };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ConfigureInput, ConnectInput, Connection } from "../types/schemas/integrations.js";
|
|
2
|
+
import "../types/index.js";
|
|
3
|
+
//#region src/integrations/model.d.ts
|
|
4
|
+
/** An org already has a connection for this integration (one per integration per org). */
|
|
5
|
+
declare class AlreadyConnectedError extends Error {
|
|
6
|
+
readonly integrationId: string;
|
|
7
|
+
constructor(integrationId: string);
|
|
8
|
+
}
|
|
9
|
+
/** The named integration is not declared in the registry. */
|
|
10
|
+
declare class UnknownIntegrationError extends Error {
|
|
11
|
+
readonly integrationId: string;
|
|
12
|
+
constructor(integrationId: string);
|
|
13
|
+
}
|
|
14
|
+
/** An action's external call failed (or the action rejected its input). */
|
|
15
|
+
declare class ActionInvocationError extends Error {
|
|
16
|
+
readonly integrationId: string;
|
|
17
|
+
readonly actionId: string;
|
|
18
|
+
constructor(integrationId: string, actionId: string, cause: unknown);
|
|
19
|
+
}
|
|
20
|
+
/** The config was rejected by the integration's validator. */
|
|
21
|
+
declare class InvalidConfigError extends Error {
|
|
22
|
+
readonly integrationId: string;
|
|
23
|
+
readonly errors: string[];
|
|
24
|
+
constructor(integrationId: string, errors: string[]);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { ActionInvocationError, AlreadyConnectedError, type ConfigureInput, type ConnectInput, type Connection, InvalidConfigError, UnknownIntegrationError };
|
|
28
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/integrations/model.ts
|
|
2
|
+
/** An org already has a connection for this integration (one per integration per org). */
|
|
3
|
+
var AlreadyConnectedError = class extends Error {
|
|
4
|
+
integrationId;
|
|
5
|
+
constructor(integrationId) {
|
|
6
|
+
super(`a connection for "${integrationId}" already exists`);
|
|
7
|
+
this.integrationId = integrationId;
|
|
8
|
+
this.name = "AlreadyConnectedError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/** The named integration is not declared in the registry. */
|
|
12
|
+
var UnknownIntegrationError = class extends Error {
|
|
13
|
+
integrationId;
|
|
14
|
+
constructor(integrationId) {
|
|
15
|
+
super(`unknown integration "${integrationId}"`);
|
|
16
|
+
this.integrationId = integrationId;
|
|
17
|
+
this.name = "UnknownIntegrationError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/** An action's external call failed (or the action rejected its input). */
|
|
21
|
+
var ActionInvocationError = class extends Error {
|
|
22
|
+
integrationId;
|
|
23
|
+
actionId;
|
|
24
|
+
constructor(integrationId, actionId, cause) {
|
|
25
|
+
super(`action "${integrationId}.${actionId}" failed: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
26
|
+
this.integrationId = integrationId;
|
|
27
|
+
this.actionId = actionId;
|
|
28
|
+
this.name = "ActionInvocationError";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/** The config was rejected by the integration's validator. */
|
|
32
|
+
var InvalidConfigError = class extends Error {
|
|
33
|
+
integrationId;
|
|
34
|
+
errors;
|
|
35
|
+
constructor(integrationId, errors) {
|
|
36
|
+
super(`invalid config for "${integrationId}": ${errors.join("; ")}`);
|
|
37
|
+
this.integrationId = integrationId;
|
|
38
|
+
this.errors = errors;
|
|
39
|
+
this.name = "InvalidConfigError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ActionInvocationError, AlreadyConnectedError, InvalidConfigError, UnknownIntegrationError };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","names":[],"sources":["../../src/integrations/model.ts"],"sourcesContent":["// integrations context — entities & DTOs are owned by @headless-lms/core/types;\n// the domain errors below are runtime code and stay in core.\nexport type { Connection, ConnectInput, ConfigureInput } from '../types/index.js';\n\n/** An org already has a connection for this integration (one per integration per org). */\nexport class AlreadyConnectedError extends Error {\n constructor(readonly integrationId: string) {\n super(`a connection for \"${integrationId}\" already exists`);\n this.name = 'AlreadyConnectedError';\n }\n}\n\n/** The named integration is not declared in the registry. */\nexport class UnknownIntegrationError extends Error {\n constructor(readonly integrationId: string) {\n super(`unknown integration \"${integrationId}\"`);\n this.name = 'UnknownIntegrationError';\n }\n}\n\n/** An action's external call failed (or the action rejected its input). */\nexport class ActionInvocationError extends Error {\n constructor(\n readonly integrationId: string,\n readonly actionId: string,\n cause: unknown,\n ) {\n super(\n `action \"${integrationId}.${actionId}\" failed: ${\n cause instanceof Error ? cause.message : String(cause)\n }`,\n );\n this.name = 'ActionInvocationError';\n }\n}\n\n/** The config was rejected by the integration's validator. */\nexport class InvalidConfigError extends Error {\n constructor(\n readonly integrationId: string,\n readonly errors: string[],\n ) {\n super(`invalid config for \"${integrationId}\": ${errors.join('; ')}`);\n this.name = 'InvalidConfigError';\n }\n}\n"],"mappings":";;AAKA,IAAa,wBAAb,cAA2C,MAAM;CAC1B;CAArB,YAAY,eAAgC;EAC1C,MAAM,qBAAqB,cAAc,iBAAiB;EADvC,KAAA,gBAAA;EAEnB,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,0BAAb,cAA6C,MAAM;CAC5B;CAArB,YAAY,eAAgC;EAC1C,MAAM,wBAAwB,cAAc,EAAE;EAD3B,KAAA,gBAAA;EAEnB,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,wBAAb,cAA2C,MAAM;CAEpC;CACA;CAFX,YACE,eACA,UACA,OACA;EACA,MACE,WAAW,cAAc,GAAG,SAAS,YACnC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEzD;EARS,KAAA,gBAAA;EACA,KAAA,WAAA;EAQT,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,qBAAb,cAAwC,MAAM;CAEjC;CACA;CAFX,YACE,eACA,QACA;EACA,MAAM,uBAAuB,cAAc,KAAK,OAAO,KAAK,IAAI,GAAG;EAH1D,KAAA,gBAAA;EACA,KAAA,SAAA;EAGT,KAAK,OAAO;CACd;AACF"}
|