@dotbep/core 0.2.7 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/index.d.ts +7 -5
  2. package/dist/index.js +604 -596
  3. package/package.json +4 -1
  4. package/examples/01-participants.ts +0 -127
  5. package/examples/02-files.ts +0 -100
  6. package/examples/03-workflows.ts +0 -149
  7. package/examples/04-bim-uses.ts +0 -70
  8. package/examples/05-standards.ts +0 -60
  9. package/examples/06-schedule.ts +0 -124
  10. package/examples/07-loin.ts +0 -133
  11. package/examples/08-deliverables.ts +0 -126
  12. package/examples/09-notes.ts +0 -73
  13. package/examples/10-llm.ts +0 -109
  14. package/examples/11-resolved.ts +0 -133
  15. package/examples/12-history.ts +0 -166
  16. package/examples/13-engine.ts +0 -152
  17. package/examples/bep.d.ts +0 -38
  18. package/examples/example.bep +0 -0
  19. package/examples/run-all.ts +0 -38
  20. package/src/base/entity.ts +0 -148
  21. package/src/base/history.ts +0 -497
  22. package/src/base/index.ts +0 -5
  23. package/src/base/singleton.ts +0 -26
  24. package/src/entities/actions.ts +0 -25
  25. package/src/entities/adapters.ts +0 -16
  26. package/src/entities/annexes.ts +0 -17
  27. package/src/entities/assetTypes.ts +0 -30
  28. package/src/entities/automations.ts +0 -24
  29. package/src/entities/bimUses.ts +0 -50
  30. package/src/entities/deliverables.ts +0 -66
  31. package/src/entities/disciplines.ts +0 -21
  32. package/src/entities/effects.ts +0 -28
  33. package/src/entities/env.ts +0 -17
  34. package/src/entities/events.ts +0 -24
  35. package/src/entities/extensions.ts +0 -16
  36. package/src/entities/flags.ts +0 -17
  37. package/src/entities/guides.ts +0 -26
  38. package/src/entities/index.ts +0 -32
  39. package/src/entities/lbsNodes.ts +0 -193
  40. package/src/entities/lods.ts +0 -22
  41. package/src/entities/loin.ts +0 -127
  42. package/src/entities/lois.ts +0 -22
  43. package/src/entities/members.ts +0 -137
  44. package/src/entities/milestones.ts +0 -32
  45. package/src/entities/notes.ts +0 -27
  46. package/src/entities/objectives.ts +0 -17
  47. package/src/entities/phases.ts +0 -17
  48. package/src/entities/remoteData.ts +0 -17
  49. package/src/entities/resolvers.ts +0 -20
  50. package/src/entities/roles.ts +0 -29
  51. package/src/entities/softwares.ts +0 -26
  52. package/src/entities/standards.ts +0 -68
  53. package/src/entities/teams.ts +0 -42
  54. package/src/entities/workflows.ts +0 -256
  55. package/src/index.ts +0 -464
  56. package/src/runtime/Engine.ts +0 -352
  57. package/src/runtime/MemoryStorage.ts +0 -31
  58. package/src/runtime/Runtime.ts +0 -106
  59. package/src/runtime/index.ts +0 -4
  60. package/src/runtime/transitions.ts +0 -456
  61. package/src/runtime/types.ts +0 -279
  62. package/src/types/history.ts +0 -37
  63. package/src/types/index.ts +0 -24
  64. package/src/types/resolved.ts +0 -137
  65. package/src/types/schema.ts +0 -757
  66. package/src/utils/diff.ts +0 -109
  67. package/src/utils/index.ts +0 -9
  68. package/src/utils/integrity.ts +0 -108
  69. package/src/utils/lbs.ts +0 -116
  70. package/src/utils/mermaid.ts +0 -110
  71. package/src/utils/naming.ts +0 -62
  72. package/src/utils/nomenclature.ts +0 -107
  73. package/src/utils/normalize.ts +0 -35
  74. package/src/utils/raci.ts +0 -25
  75. package/src/utils/textFile.ts +0 -24
  76. package/tsconfig.json +0 -12
  77. package/vite.config.ts +0 -24
@@ -1,137 +0,0 @@
1
- import type { BEP, Member, Team } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { MemberSchema } from '../types/schema.js'
4
- import type { MemberResolved } from '../types/resolved.js'
5
-
6
- export class Members extends Entity<Member> {
7
- constructor(getBep: () => BEP) {
8
- super(
9
- () => getBep().members,
10
- getBep,
11
- {
12
- key: 'members',
13
- idField: 'email',
14
- schema: MemberSchema,
15
- },
16
- )
17
- }
18
-
19
- listResolved(): MemberResolved[] {
20
- const bep = this.getBep()
21
- return bep.members.map(m => {
22
- const team = bep.teams.find(t => (t.memberEmails ?? []).includes(m.email))
23
- return {
24
- ...m,
25
- role: bep.roles.find(r => r.id === m.roleId) ?? null,
26
- team: team ? { id: team.id, name: team.name } : null,
27
- isRepresentative: team?.representativeEmail === m.email,
28
- }
29
- })
30
- }
31
-
32
- addToTeam(items: Array<Member & { teamId: Team['id']; isRepresentative?: boolean }>): {
33
- succeeded: MemberResolved[]
34
- failed: { input: unknown; error: string }[]
35
- } {
36
- const succeeded: MemberResolved[] = []
37
- const failed: { input: unknown; error: string }[] = []
38
-
39
- for (const item of items) {
40
- const bep = this.getBep()
41
- const team = bep.teams.find(t => t.id === item.teamId)
42
- if (!team) { failed.push({ input: item, error: `Team not found: ${item.teamId}` }); continue }
43
-
44
- const { teamId, isRepresentative, ...member } = item
45
- const result = this.add([member])
46
- if (result.failed.length > 0) { failed.push({ input: item, error: result.failed[0].error }); continue }
47
-
48
- team.memberEmails ??= []
49
- if (!team.memberEmails.includes(item.email)) team.memberEmails.push(item.email)
50
- if (isRepresentative) team.representativeEmail = item.email
51
-
52
- const resolved = this.listResolved().find(m => m.email === item.email)!
53
- succeeded.push(resolved)
54
- }
55
-
56
- return { succeeded, failed }
57
- }
58
-
59
- updateInTeam(items: Array<Partial<Member> & { email: Member['email']; teamId?: Team['id']; isRepresentative?: boolean }>): {
60
- succeeded: Array<{ email: Member['email']; after: MemberResolved }>
61
- failed: { email: Member['email']; error: string }[]
62
- } {
63
- const succeeded: Array<{ email: Member['email']; after: MemberResolved }> = []
64
- const failed: { email: Member['email']; error: string }[] = []
65
-
66
- for (const item of items) {
67
- const bep = this.getBep()
68
- const { teamId, isRepresentative, ...fields } = item
69
-
70
- if (teamId !== undefined && !bep.teams.find(t => t.id === teamId)) {
71
- failed.push({ email: item.email, error: `Team not found: ${teamId}` }); continue
72
- }
73
-
74
- const result = this.update([fields])
75
- if (result.failed.length > 0) { failed.push({ email: item.email, error: result.failed[0].error }); continue }
76
-
77
- if (teamId !== undefined) {
78
- const newTeam = bep.teams.find(t => t.id === teamId)!
79
- const oldTeam = bep.teams.find(t => (t.memberEmails ?? []).includes(item.email))
80
- if (oldTeam && oldTeam.id !== teamId) {
81
- oldTeam.memberEmails = (oldTeam.memberEmails ?? []).filter(e => e !== item.email)
82
- if (oldTeam.representativeEmail === item.email) oldTeam.representativeEmail = undefined
83
- }
84
- newTeam.memberEmails ??= []
85
- if (!newTeam.memberEmails.includes(item.email)) newTeam.memberEmails.push(item.email)
86
- }
87
-
88
- if (isRepresentative !== undefined) {
89
- const team = bep.teams.find(t => (t.memberEmails ?? []).includes(item.email))
90
- if (team) team.representativeEmail = isRepresentative ? item.email : (team.representativeEmail === item.email ? undefined : team.representativeEmail)
91
- }
92
-
93
- const resolved = this.listResolved().find(m => m.email === item.email)!
94
- succeeded.push({ email: item.email, after: resolved })
95
- }
96
-
97
- return { succeeded, failed }
98
- }
99
-
100
- removeFromBep(emails: Member['email'][]): {
101
- succeeded: MemberResolved[]
102
- failed: { email: Member['email']; error: string }[]
103
- } {
104
- const succeeded: MemberResolved[] = []
105
- const failed: { email: Member['email']; error: string }[] = []
106
-
107
- for (const email of emails) {
108
- const bep = this.getBep()
109
- const snapshot = this.listResolved().find(m => m.email === email)
110
- if (!snapshot) { failed.push({ email, error: `Not found: ${email}` }); continue }
111
-
112
- // Clean team refs so integrity check doesn't block removal
113
- for (const t of bep.teams) {
114
- if (t.memberEmails) t.memberEmails = t.memberEmails.filter(e => e !== email)
115
- if (t.representativeEmail === email) t.representativeEmail = undefined
116
- }
117
-
118
- const result = this.remove([email])
119
- if (result.failed.length > 0) {
120
- // Restore team refs on failure (e.g. notes blocking)
121
- if (snapshot.team) {
122
- const team = bep.teams.find(t => t.id === snapshot.team!.id)
123
- if (team) {
124
- team.memberEmails ??= []
125
- if (!team.memberEmails.includes(email)) team.memberEmails.push(email)
126
- if (snapshot.isRepresentative) team.representativeEmail = email
127
- }
128
- }
129
- failed.push({ email, error: result.failed[0].error }); continue
130
- }
131
-
132
- succeeded.push(snapshot)
133
- }
134
-
135
- return { succeeded, failed }
136
- }
137
- }
@@ -1,32 +0,0 @@
1
- import type { BEP, Milestone } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { MilestoneSchema } from '../types/schema.js'
4
- import type { MilestoneResolved } from '../types/resolved.js'
5
-
6
- export class Milestones extends Entity<Milestone, true> {
7
- constructor(getBep: () => BEP) {
8
- super(
9
- () => getBep().milestones,
10
- getBep,
11
- {
12
- key: 'milestones',
13
- schema: MilestoneSchema,
14
- autoId: true,
15
- beforeRemove: (id, bep) => {
16
- for (const loin of bep.loin) {
17
- const ref = loin.milestones?.find(m => m.milestoneId === id)
18
- if (ref) throw new Error(`Referenced by: loin["${loin.id}"].milestones[milestoneId="${id}"]`)
19
- }
20
- },
21
- },
22
- )
23
- }
24
-
25
- listResolved(): MilestoneResolved[] {
26
- const bep = this.getBep()
27
- return bep.milestones.map(m => ({
28
- ...m,
29
- phase: bep.phases.find(p => p.id === m.phaseId) ?? null,
30
- }))
31
- }
32
- }
@@ -1,27 +0,0 @@
1
- import type { BEP, Note } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { NoteSchema } from '../types/schema.js'
4
- import type { NoteResolved } from '../types/resolved.js'
5
- import type { Members } from './members.js'
6
-
7
- export class Notes extends Entity<Note, true> {
8
- constructor(getBep: () => BEP, private readonly getMembers: () => Members) {
9
- super(
10
- () => getBep().notes,
11
- getBep,
12
- {
13
- key: 'notes',
14
- schema: NoteSchema,
15
- autoId: true,
16
- },
17
- )
18
- }
19
-
20
- listResolved(): NoteResolved[] {
21
- const memberMap = new Map(this.getMembers().listResolved().map(m => [m.email, m]))
22
- return this.getBep().notes.map(n => ({
23
- ...n,
24
- member: memberMap.get(n.memberEmail) ?? null,
25
- }))
26
- }
27
- }
@@ -1,17 +0,0 @@
1
- import type { BEP, Objective } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { ObjectiveSchema } from '../types/schema.js'
4
-
5
- export class Objectives extends Entity<Objective, true> {
6
- constructor(getBep: () => BEP) {
7
- super(
8
- () => getBep().objectives,
9
- getBep,
10
- {
11
- key: 'objectives',
12
- schema: ObjectiveSchema,
13
- autoId: true,
14
- },
15
- )
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import type { BEP, Phase } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { PhaseSchema } from '../types/schema.js'
4
-
5
- export class Phases extends Entity<Phase, true> {
6
- constructor(getBep: () => BEP) {
7
- super(
8
- () => getBep().phases,
9
- getBep,
10
- {
11
- key: 'phases',
12
- schema: PhaseSchema,
13
- autoId: true,
14
- },
15
- )
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import type { BEP, RemoteData } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { RemoteDataSchema } from '../types/schema.js'
4
-
5
- export class RemoteDataEntity extends Entity<RemoteData, true> {
6
- constructor(getBep: () => BEP) {
7
- super(
8
- () => getBep().remoteData,
9
- getBep,
10
- {
11
- key: 'remoteData',
12
- schema: RemoteDataSchema,
13
- autoId: true,
14
- },
15
- )
16
- }
17
- }
@@ -1,20 +0,0 @@
1
- import type { BEP, Resolver } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { ResolverSchema } from '../types/schema.js'
4
-
5
- export class Resolvers extends Entity<Resolver> {
6
- constructor(getBep: () => BEP) {
7
- super(
8
- () => getBep().resolvers,
9
- getBep,
10
- {
11
- key: 'resolvers',
12
- schema: ResolverSchema,
13
- beforeRemove: (id, bep) => {
14
- const ref = bep.remoteData.find(r => r.resolverId === id)
15
- if (ref) throw new Error(`Referenced by: remoteData["${ref.id}"].resolverId`)
16
- },
17
- },
18
- )
19
- }
20
- }
@@ -1,29 +0,0 @@
1
- import type { BEP, Role } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { RoleSchema } from '../types/schema.js'
4
-
5
- export class Roles extends Entity<Role, true> {
6
- constructor(getBep: () => BEP) {
7
- super(
8
- () => getBep().roles,
9
- getBep,
10
- {
11
- key: 'roles',
12
- schema: RoleSchema,
13
- autoId: true,
14
- beforeRemove: (id, bep) => {
15
- const raciFields = ['responsibleRoleIds', 'accountableRoleIds', 'consultedRoleIds', 'informedRoleIds'] as const
16
- for (const wf of bep.workflows) {
17
- for (const [nodeKey, node] of Object.entries(wf.diagram.nodes)) {
18
- if (node.type !== 'process') continue
19
- for (const field of raciFields) {
20
- if (node[field]?.includes(id))
21
- throw new Error(`Referenced by: workflows["${wf.id}"].diagram.nodes["${nodeKey}"].${field}`)
22
- }
23
- }
24
- }
25
- },
26
- },
27
- )
28
- }
29
- }
@@ -1,26 +0,0 @@
1
- import type { BEP, Software } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { SoftwareSchema } from '../types/schema.js'
4
- import type { AssetTypeResolved, SoftwareResolved } from '../types/resolved.js'
5
- import type { AssetTypes } from './assetTypes.js'
6
-
7
- export class Softwares extends Entity<Software> {
8
- constructor(getBep: () => BEP, private readonly getAssetTypes: () => AssetTypes) {
9
- super(
10
- () => getBep().softwares,
11
- getBep,
12
- {
13
- key: 'softwares',
14
- schema: SoftwareSchema,
15
- },
16
- )
17
- }
18
-
19
- listResolved(): SoftwareResolved[] {
20
- const assetTypeMap = new Map(this.getAssetTypes().listResolved().map(dt => [dt.id, dt]))
21
- return this.getBep().softwares.map(s => ({
22
- ...s,
23
- assetTypes: (s.assetTypeIds ?? []).map(id => assetTypeMap.get(id)).filter(Boolean) as AssetTypeResolved[],
24
- }))
25
- }
26
- }
@@ -1,68 +0,0 @@
1
- import type JSZip from 'jszip'
2
- import type { BEP, Standard } from '../types/schema.js'
3
- import { Entity, type BulkResult } from '../base/entity.js'
4
- import { StandardSchema } from '../types/schema.js'
5
-
6
- /** Input for Standards.add(): accepts markdown text in `content` instead of a file path. */
7
- export type StandardAddInput = Omit<Standard, 'id' | 'contentPath'> & { content: string }
8
-
9
- export class Standards extends Entity<Standard, true> {
10
- constructor(getBep: () => BEP, private getZip: () => JSZip) {
11
- super(
12
- () => getBep().standards,
13
- getBep,
14
- { key: 'standards', schema: StandardSchema, autoId: true },
15
- )
16
- }
17
-
18
- /**
19
- * Accepts markdown text in `content` (user-facing).
20
- * Generates a UUID-based path, writes the text to the zip,
21
- * and stores the path in Standard.contentPath.
22
- * Union with AddInput<Standard> satisfies the base class contract.
23
- */
24
- override add(inputs: (StandardAddInput | Omit<Standard, 'id'>)[]): BulkResult<Standard> {
25
- const withPaths = inputs.map(input => {
26
- const path = `standards/${globalThis.crypto.randomUUID()}.md`
27
- if ('content' in input) {
28
- const { content, ...rest } = input
29
- this.getZip().file(path, content)
30
- return { ...rest, contentPath: path }
31
- }
32
- this.getZip().file(path, '')
33
- return { ...input, contentPath: path }
34
- })
35
- return super.add(withPaths)
36
- }
37
-
38
- /** Removes standards and deletes their .md files from the zip. */
39
- override remove(ids: Standard['id'][]) {
40
- const paths = new Map(
41
- ids
42
- .map(id => [id, this.list().find(s => s.id === id)?.contentPath])
43
- .filter((e): e is [string, string] => e[1] !== undefined),
44
- )
45
- const result = super.remove(ids)
46
- for (const id of result.succeeded) {
47
- const path = paths.get(id)
48
- if (path) this.getZip().remove(path)
49
- }
50
- return result
51
- }
52
-
53
- /** Returns the markdown text content of the given standard. */
54
- async getContent(id: Standard['id']): Promise<string> {
55
- const std = this.list().find(s => s.id === id)
56
- if (!std) throw new Error(`Standard not found: ${id}`)
57
- const file = this.getZip().file(std.contentPath)
58
- if (!file) throw new Error(`Content file not found: ${std.contentPath}`)
59
- return file.async('string')
60
- }
61
-
62
- /** Writes new markdown text content for the given standard. */
63
- setContent(id: Standard['id'], text: string): void {
64
- const std = this.list().find(s => s.id === id)
65
- if (!std) throw new Error(`Standard not found: ${id}`)
66
- this.getZip().file(std.contentPath, text)
67
- }
68
- }
@@ -1,42 +0,0 @@
1
- import type { BEP, Discipline, Team } from '../types/schema.js'
2
- import { Entity } from '../base/entity.js'
3
- import { TeamSchema } from '../types/schema.js'
4
- import type { MemberResolved, TeamResolved } from '../types/resolved.js'
5
- import type { Members } from './members.js'
6
- import { validateTokenValue } from '../utils/naming.js'
7
-
8
- export class Teams extends Entity<Team> {
9
- constructor(getBep: () => BEP, private readonly getMembers: () => Members) {
10
- super(
11
- () => getBep().teams,
12
- getBep,
13
- {
14
- key: 'teams',
15
- schema: TeamSchema,
16
- validate: (team, bep) => {
17
- const errors: string[] = []
18
- const tokenErr = validateTokenValue('team', team.id, bep.deliverableNamingConvention)
19
- if (tokenErr) errors.push(tokenErr)
20
- if (team.representativeEmail && !(team.memberEmails ?? []).includes(team.representativeEmail))
21
- errors.push(`representativeEmail "${team.representativeEmail}" is not a member of this team`)
22
- return errors
23
- },
24
- beforeRemove: (id, bep) => {
25
- if (bep.project.clientId === id)
26
- throw new Error('Referenced by: project.clientId')
27
- },
28
- },
29
- )
30
- }
31
-
32
- listResolved(): TeamResolved[] {
33
- const bep = this.getBep()
34
- const memberMap = new Map(this.getMembers().listResolved().map(m => [m.email, m]))
35
- return bep.teams.map(t => ({
36
- ...t,
37
- representative: memberMap.get(t.representativeEmail ?? '') ?? null,
38
- members: (t.memberEmails ?? []).map(email => memberMap.get(email)).filter(Boolean) as MemberResolved[],
39
- disciplines: (t.disciplineIds ?? []).map(id => bep.disciplines.find(d => d.id === id)).filter(Boolean) as Discipline[],
40
- }))
41
- }
42
- }