@dotbep/core 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -40
- package/dist/index.js +1142 -1179
- package/package.json +4 -1
- package/examples/01-participants.ts +0 -127
- package/examples/02-files.ts +0 -100
- package/examples/03-workflows.ts +0 -149
- package/examples/04-bim-uses.ts +0 -70
- package/examples/05-standards.ts +0 -60
- package/examples/06-schedule.ts +0 -124
- package/examples/07-loin.ts +0 -133
- package/examples/08-deliverables.ts +0 -126
- package/examples/09-notes.ts +0 -73
- package/examples/10-llm.ts +0 -109
- package/examples/11-resolved.ts +0 -133
- package/examples/12-history.ts +0 -166
- package/examples/13-engine.ts +0 -152
- package/examples/bep.d.ts +0 -38
- package/examples/example.bep +0 -0
- package/examples/run-all.ts +0 -38
- package/src/base/entity.ts +0 -148
- package/src/base/history.ts +0 -497
- package/src/base/index.ts +0 -5
- package/src/base/singleton.ts +0 -26
- package/src/entities/actions.ts +0 -25
- package/src/entities/adapters.ts +0 -16
- package/src/entities/annexes.ts +0 -17
- package/src/entities/assetTypes.ts +0 -30
- package/src/entities/automations.ts +0 -24
- package/src/entities/bimUses.ts +0 -50
- package/src/entities/deliverables.ts +0 -66
- package/src/entities/disciplines.ts +0 -21
- package/src/entities/effects.ts +0 -28
- package/src/entities/env.ts +0 -17
- package/src/entities/events.ts +0 -24
- package/src/entities/extensions.ts +0 -16
- package/src/entities/flags.ts +0 -17
- package/src/entities/guides.ts +0 -26
- package/src/entities/index.ts +0 -32
- package/src/entities/lbsNodes.ts +0 -193
- package/src/entities/lods.ts +0 -22
- package/src/entities/loin.ts +0 -127
- package/src/entities/lois.ts +0 -22
- package/src/entities/members.ts +0 -137
- package/src/entities/milestones.ts +0 -32
- package/src/entities/notes.ts +0 -27
- package/src/entities/objectives.ts +0 -17
- package/src/entities/phases.ts +0 -17
- package/src/entities/remoteData.ts +0 -17
- package/src/entities/resolvers.ts +0 -20
- package/src/entities/roles.ts +0 -29
- package/src/entities/softwares.ts +0 -26
- package/src/entities/standards.ts +0 -68
- package/src/entities/teams.ts +0 -42
- package/src/entities/workflows.ts +0 -256
- package/src/index.ts +0 -464
- package/src/runtime/Engine.ts +0 -352
- package/src/runtime/MemoryStorage.ts +0 -31
- package/src/runtime/Runtime.ts +0 -106
- package/src/runtime/index.ts +0 -4
- package/src/runtime/transitions.ts +0 -456
- package/src/runtime/types.ts +0 -279
- package/src/types/history.ts +0 -37
- package/src/types/index.ts +0 -24
- package/src/types/resolved.ts +0 -137
- package/src/types/schema.ts +0 -757
- package/src/utils/diff.ts +0 -109
- package/src/utils/index.ts +0 -9
- package/src/utils/integrity.ts +0 -108
- package/src/utils/lbs.ts +0 -116
- package/src/utils/mermaid.ts +0 -110
- package/src/utils/naming.ts +0 -62
- package/src/utils/nomenclature.ts +0 -107
- package/src/utils/normalize.ts +0 -35
- package/src/utils/raci.ts +0 -25
- package/src/utils/textFile.ts +0 -24
- package/tsconfig.json +0 -12
- package/vite.config.ts +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotbep/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
13
16
|
"publishConfig": {
|
|
14
17
|
"access": "public"
|
|
15
18
|
},
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
// run: node --experimental-strip-types examples/01-participants.ts (from core/)
|
|
2
|
-
//
|
|
3
|
-
// Covers: Bep.create(), roles, teams, members.
|
|
4
|
-
//
|
|
5
|
-
// A BEP starts with its participants: who is involved, what role they play,
|
|
6
|
-
// and which organization they belong to. This example builds that foundation.
|
|
7
|
-
//
|
|
8
|
-
// Roles describe functional responsibilities within the project (e.g. BIM Manager).
|
|
9
|
-
// Teams represent the contracting organizations (e.g. the architecture firm).
|
|
10
|
-
// Members are the individual people — each identified by email and assigned a role.
|
|
11
|
-
//
|
|
12
|
-
// The dependency chain is: Role ← Member ← Team. A member references a role;
|
|
13
|
-
// a team references its members. Deleting in the wrong order is blocked by
|
|
14
|
-
// referential integrity, as shown at the end of each section.
|
|
15
|
-
|
|
16
|
-
import { writeFileSync } from 'node:fs'
|
|
17
|
-
import { Bep } from '../dist/index.js'
|
|
18
|
-
|
|
19
|
-
const bep = Bep.create({ name: 'Example Project', code: 'EXP' })
|
|
20
|
-
|
|
21
|
-
// ─── Roles ────────────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
// Roles are the functional positions that appear in RACI matrices and workflow
|
|
24
|
-
// diagrams. They are project-level, not tied to a specific person or team.
|
|
25
|
-
// The id is auto-generated (UUID) — capture it from the result to use later.
|
|
26
|
-
|
|
27
|
-
console.log('=== roles ===')
|
|
28
|
-
|
|
29
|
-
const rolesAdded = bep.roles.add([
|
|
30
|
-
{ name: 'BIM Manager', color: '#E63946' },
|
|
31
|
-
{ name: 'BIM Coordinator', color: '#4444FF' },
|
|
32
|
-
])
|
|
33
|
-
const roleManagerId = rolesAdded.succeeded[0].id
|
|
34
|
-
const roleCoordId = rolesAdded.succeeded[1].id
|
|
35
|
-
console.log('add succeeded:', rolesAdded.succeeded.map(r => r.name))
|
|
36
|
-
|
|
37
|
-
// update() is a sparse patch — only the fields included in the call are touched.
|
|
38
|
-
// Sending { id, color } leaves name and every other field unchanged.
|
|
39
|
-
const rolesUpdated = bep.roles.update([
|
|
40
|
-
{ id: roleManagerId, color: '#C1121F' },
|
|
41
|
-
{ id: 'ghost-uuid', color: '#000000' }, // fails — id not found
|
|
42
|
-
])
|
|
43
|
-
console.log('update succeeded:', rolesUpdated.succeeded.map(r => r.id))
|
|
44
|
-
console.log('update failed: ', rolesUpdated.failed)
|
|
45
|
-
|
|
46
|
-
// ─── Teams ────────────────────────────────────────────────────────────────────
|
|
47
|
-
|
|
48
|
-
// Teams represent the contracting parties defined in the appointment documents.
|
|
49
|
-
// Their id is a short readable code (e.g. 'ARC') that appears in deliverable
|
|
50
|
-
// naming codes, so it must be chosen carefully — it is not auto-generated.
|
|
51
|
-
// isoRole maps to the ISO 19650 appointment roles (lead-appointed-party, etc.).
|
|
52
|
-
|
|
53
|
-
console.log('\n=== teams ===')
|
|
54
|
-
|
|
55
|
-
const teamsAdded = bep.teams.add([
|
|
56
|
-
{ id: 'ARC', name: 'Architecture', isoRole: 'lead-appointed-party' },
|
|
57
|
-
{ id: 'STR', name: 'Structure', isoRole: 'appointed-party' },
|
|
58
|
-
{ id: 'ARC', name: 'Duplicate', isoRole: 'appointed-party' }, // fails — duplicate id
|
|
59
|
-
])
|
|
60
|
-
console.log('add succeeded:', teamsAdded.succeeded.map(t => t.id))
|
|
61
|
-
console.log('add failed: ', teamsAdded.failed)
|
|
62
|
-
|
|
63
|
-
bep.teams.update([{ id: 'ARC', name: 'Architecture (Lead)' }])
|
|
64
|
-
|
|
65
|
-
// A team with no references can be freely removed.
|
|
66
|
-
const strRemoved = bep.teams.remove(['STR', 'XXX'])
|
|
67
|
-
console.log('remove STR succeeded:', strRemoved.succeeded)
|
|
68
|
-
console.log('remove XXX failed: ', strRemoved.failed)
|
|
69
|
-
|
|
70
|
-
// project.clientId is set directly on bep.data — the client team is the
|
|
71
|
-
// appointing party and is referenced at the project level.
|
|
72
|
-
bep.data.project.clientId = 'ARC'
|
|
73
|
-
|
|
74
|
-
// Once a team is the project client, removing it would leave project.clientId
|
|
75
|
-
// pointing to a non-existent entity — integrity blocks the operation.
|
|
76
|
-
console.log('\n--- integrity: team referenced as project.clientId cannot be removed ---')
|
|
77
|
-
const arcBlocked = bep.teams.remove(['ARC'])
|
|
78
|
-
console.log('remove ARC (blocked by project.clientId):', arcBlocked.failed)
|
|
79
|
-
|
|
80
|
-
// ─── Members ──────────────────────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
// Members are the individual people who author and approve the BEP.
|
|
83
|
-
// Email is the natural key — it must be unique across the entire BEP.
|
|
84
|
-
// Each member is assigned exactly one role; the role must already exist.
|
|
85
|
-
|
|
86
|
-
console.log('\n=== members ===')
|
|
87
|
-
|
|
88
|
-
const membersAdded = bep.members.add([
|
|
89
|
-
{ email: 'alice@arc.com', name: 'Alice Mora', roleId: roleManagerId },
|
|
90
|
-
{ email: 'bob@arc.com', name: 'Bob Rivas', roleId: roleCoordId },
|
|
91
|
-
{ email: 'alice@arc.com', name: 'Duplicate', roleId: roleManagerId }, // fails — duplicate email
|
|
92
|
-
{ email: 'ghost@x.com', name: 'Ghost', roleId: 'bad-role' }, // fails — role not found
|
|
93
|
-
])
|
|
94
|
-
console.log('add succeeded:', membersAdded.succeeded.map(m => m.email))
|
|
95
|
-
console.log('add failed: ', membersAdded.failed)
|
|
96
|
-
|
|
97
|
-
bep.members.update([
|
|
98
|
-
{ email: 'alice@arc.com', name: 'Alice Mora (BIM Manager)' },
|
|
99
|
-
{ email: 'nobody@x.com', name: 'Ghost' }, // fails — email not found
|
|
100
|
-
])
|
|
101
|
-
|
|
102
|
-
// Teams are linked to their members via memberEmails. The representative is
|
|
103
|
-
// the single point of contact for the team — also referenced by email.
|
|
104
|
-
bep.teams.update([{
|
|
105
|
-
id: 'ARC',
|
|
106
|
-
memberEmails: ['alice@arc.com', 'bob@arc.com'],
|
|
107
|
-
representativeEmail: 'alice@arc.com',
|
|
108
|
-
}])
|
|
109
|
-
|
|
110
|
-
// A member referenced by a team's memberEmails cannot be removed — doing so
|
|
111
|
-
// would silently orphan the team's roster.
|
|
112
|
-
console.log('\n--- integrity: member referenced by team cannot be removed ---')
|
|
113
|
-
const aliceBlocked = bep.members.remove(['alice@arc.com'])
|
|
114
|
-
console.log('remove alice (blocked by team.memberEmails):', aliceBlocked.failed)
|
|
115
|
-
|
|
116
|
-
// Similarly, a role referenced by any member cannot be removed — the member
|
|
117
|
-
// would be left without a valid functional role in the BEP.
|
|
118
|
-
console.log('\n--- integrity: role referenced by member cannot be removed ---')
|
|
119
|
-
const roleBlocked = bep.roles.remove([roleManagerId])
|
|
120
|
-
console.log('remove BIM Manager (blocked by alice.roleId):', roleBlocked.failed)
|
|
121
|
-
|
|
122
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
123
|
-
|
|
124
|
-
// save() returns a Buffer — the .bep zip in memory. Writing it to disk is the
|
|
125
|
-
// caller's responsibility; the core has no filesystem dependency.
|
|
126
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
127
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/02-files.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --02 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: disciplines, extensions, assetTypes, softwares.
|
|
4
|
-
//
|
|
5
|
-
// These entities describe the file ecosystem of the project: what kinds of
|
|
6
|
-
// documents are produced, in which formats, with which tools, and under which
|
|
7
|
-
// discipline. They are referenced heavily by deliverables and LOIN entries.
|
|
8
|
-
//
|
|
9
|
-
// The dependency chain is:
|
|
10
|
-
// Extension ← AssetType ← Software
|
|
11
|
-
//
|
|
12
|
-
// Disciplines are orthogonal to that chain — they classify the authoring
|
|
13
|
-
// responsibility (Architecture, Structure, MEP…) and appear in deliverable
|
|
14
|
-
// naming codes and LOIN entries.
|
|
15
|
-
|
|
16
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
17
|
-
import { Bep } from '../dist/index.js'
|
|
18
|
-
|
|
19
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
20
|
-
|
|
21
|
-
// ─── Disciplines ──────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
// Disciplines identify the engineering domain responsible for a set of
|
|
24
|
-
// deliverables. Their id is a short readable code (e.g. 'ARQ') that appears
|
|
25
|
-
// directly in naming codes — choose it to match the project convention.
|
|
26
|
-
|
|
27
|
-
console.log('=== disciplines ===')
|
|
28
|
-
|
|
29
|
-
bep.disciplines.add([
|
|
30
|
-
{ id: 'ARQ', name: 'Architecture' },
|
|
31
|
-
{ id: 'EST', name: 'Structure' },
|
|
32
|
-
{ id: 'MEP', name: 'MEP' },
|
|
33
|
-
{ id: 'ARQ', name: 'Duplicate' }, // fails — duplicate id
|
|
34
|
-
])
|
|
35
|
-
console.log('list:', bep.disciplines.list().map(d => d.id))
|
|
36
|
-
|
|
37
|
-
// associate ARC with ARQ to set up an integrity constraint
|
|
38
|
-
bep.teams.update([{ id: 'ARC', disciplineIds: ['ARQ'] }])
|
|
39
|
-
|
|
40
|
-
console.log('\n--- integrity: discipline referenced by team.disciplineIds cannot be removed ---')
|
|
41
|
-
const discBlocked = bep.disciplines.remove(['ARQ'])
|
|
42
|
-
console.log('remove ARQ (blocked by ARC.disciplineIds):', discBlocked.failed)
|
|
43
|
-
|
|
44
|
-
// ─── Extensions ───────────────────────────────────────────────────────────────
|
|
45
|
-
|
|
46
|
-
// Extensions are the file formats produced by the project (ifc, rvt, pdf…).
|
|
47
|
-
// Their id is a lowercase file extension that appears in deliverable naming.
|
|
48
|
-
// They are the base of the file type chain: Extension ← AssetType ← Software.
|
|
49
|
-
|
|
50
|
-
console.log('\n=== extensions ===')
|
|
51
|
-
|
|
52
|
-
bep.extensions.add([
|
|
53
|
-
{ id: 'ifc', name: 'IFC' },
|
|
54
|
-
{ id: 'rvt', name: 'Revit' },
|
|
55
|
-
{ id: 'pdf', name: 'PDF' },
|
|
56
|
-
])
|
|
57
|
-
console.log('list:', bep.extensions.list().map(e => e.id))
|
|
58
|
-
|
|
59
|
-
// ─── AssetTypes ───────────────────────────────────────────────────────────────
|
|
60
|
-
|
|
61
|
-
// Asset types classify what a file represents (3D Model, Report, Drawing…).
|
|
62
|
-
// Each type declares which extensions it can be delivered in. A deliverable then
|
|
63
|
-
// references an asset type and optionally overrides the extension subset.
|
|
64
|
-
|
|
65
|
-
console.log('\n=== assetTypes ===')
|
|
66
|
-
|
|
67
|
-
bep.assetTypes.add([
|
|
68
|
-
{ id: 'M3D', name: '3D Model', extensionIds: ['ifc', 'rvt'] },
|
|
69
|
-
{ id: 'RPT', name: 'Report', extensionIds: ['pdf'] },
|
|
70
|
-
{ id: 'BAD', name: 'Bad Ext', extensionIds: ['ghost'] }, // fails — extension not found
|
|
71
|
-
])
|
|
72
|
-
console.log('list:', bep.assetTypes.list().map(d => d.id))
|
|
73
|
-
|
|
74
|
-
console.log('\n--- integrity: extension referenced by assetType cannot be removed ---')
|
|
75
|
-
const extBlocked = bep.extensions.remove(['ifc'])
|
|
76
|
-
console.log('remove ifc (blocked by M3D.extensionIds):', extBlocked.failed)
|
|
77
|
-
|
|
78
|
-
// ─── Softwares ────────────────────────────────────────────────────────────────
|
|
79
|
-
|
|
80
|
-
// Softwares are the authoring tools used on the project. Each one is linked to
|
|
81
|
-
// the asset types it can produce. BIM Uses reference softwares to specify
|
|
82
|
-
// which tools are required for a particular use case.
|
|
83
|
-
|
|
84
|
-
console.log('\n=== softwares ===')
|
|
85
|
-
|
|
86
|
-
bep.softwares.add([
|
|
87
|
-
{ id: 'RVT', name: 'Revit', version: '2025', assetTypeIds: ['M3D'] },
|
|
88
|
-
{ id: 'ACR', name: 'Acrobat', version: '2024', assetTypeIds: ['RPT'] },
|
|
89
|
-
{ id: 'BAD', name: 'Bad', version: '1.0', assetTypeIds: ['ghost'] }, // fails — assetType not found
|
|
90
|
-
])
|
|
91
|
-
console.log('list:', bep.softwares.list().map(s => s.id))
|
|
92
|
-
|
|
93
|
-
console.log('\n--- integrity: assetType referenced by software cannot be removed ---')
|
|
94
|
-
const dtBlocked = bep.assetTypes.remove(['M3D'])
|
|
95
|
-
console.log('remove M3D (blocked by RVT.assetTypeIds):', dtBlocked.failed)
|
|
96
|
-
|
|
97
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
98
|
-
|
|
99
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
100
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/03-workflows.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --03 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: actions, annexes, guides, workflows.
|
|
4
|
-
//
|
|
5
|
-
// Workflows are the heart of the BEP's process section. They describe how
|
|
6
|
-
// information is produced and reviewed — who does what, in what order, and
|
|
7
|
-
// under which RACI responsibility.
|
|
8
|
-
//
|
|
9
|
-
// The supporting entities build up toward the workflow:
|
|
10
|
-
// Action — an atomic step (e.g. "Update model")
|
|
11
|
-
// Annex — an external resource (video, document) that explains how to do it
|
|
12
|
-
// Guide — a named collection of annexes, attached to a workflow as reference material
|
|
13
|
-
// Workflow — the full process diagram: a FlowDiagram with nodes and edges
|
|
14
|
-
//
|
|
15
|
-
// The diagram is stored as structured JSON (FlowDiagram), not Mermaid.
|
|
16
|
-
// Mermaid is generated at runtime in the frontend via flowDiagramToMermaid().
|
|
17
|
-
// Nodes reference actions and assign RACI roles to the people responsible.
|
|
18
|
-
// Edges from process nodes must carry a triggerEventId — the event that causes
|
|
19
|
-
// the transition.
|
|
20
|
-
|
|
21
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
22
|
-
import { Bep } from '../dist/index.js'
|
|
23
|
-
|
|
24
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
25
|
-
|
|
26
|
-
// UUIDs are not stable across runs — look them up by name each time.
|
|
27
|
-
const roleManagerId = bep.roles.list().find(r => r.name === 'BIM Manager')!.id
|
|
28
|
-
|
|
29
|
-
// ─── Actions ──────────────────────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
console.log('=== actions ===')
|
|
32
|
-
|
|
33
|
-
const actionsAdded = bep.actions.add([
|
|
34
|
-
{ name: 'Update model' },
|
|
35
|
-
{ name: 'Register issues', description: 'Log in BCF' },
|
|
36
|
-
{ name: 'Review model' },
|
|
37
|
-
])
|
|
38
|
-
const actionUpdateId = actionsAdded.succeeded[0].id
|
|
39
|
-
const actionIssuesId = actionsAdded.succeeded[1].id
|
|
40
|
-
const actionReviewId = actionsAdded.succeeded[2].id
|
|
41
|
-
console.log('add succeeded:', actionsAdded.succeeded.map(a => a.name))
|
|
42
|
-
|
|
43
|
-
// ─── Events ───────────────────────────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
bep.events.add([
|
|
46
|
-
{ id: 'done', name: 'Done' },
|
|
47
|
-
])
|
|
48
|
-
|
|
49
|
-
// ─── Annexes ──────────────────────────────────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
console.log('\n=== annexes ===')
|
|
52
|
-
|
|
53
|
-
const annexesAdded = bep.annexes.add([
|
|
54
|
-
{ name: 'IFC Tutorial', type: 'video', url: 'https://example.com/ifc' },
|
|
55
|
-
{ name: 'BIM Guide', type: 'document', url: 'guides/bim-guide.pdf' },
|
|
56
|
-
])
|
|
57
|
-
const anx1Id = annexesAdded.succeeded[0].id
|
|
58
|
-
const anx2Id = annexesAdded.succeeded[1].id
|
|
59
|
-
console.log('add succeeded:', annexesAdded.succeeded.map(a => a.name))
|
|
60
|
-
|
|
61
|
-
// ─── Guides ───────────────────────────────────────────────────────────────────
|
|
62
|
-
|
|
63
|
-
console.log('\n=== guides ===')
|
|
64
|
-
|
|
65
|
-
const guidesAdded = bep.guides.add([
|
|
66
|
-
{ name: 'IFC Export Guide', annexIds: [anx1Id, anx2Id] },
|
|
67
|
-
{ name: 'Coordination Guide' },
|
|
68
|
-
{ name: 'Bad Annex Ref', annexIds: ['ghost'] }, // fails — annex not found
|
|
69
|
-
])
|
|
70
|
-
console.log('add succeeded:', guidesAdded.succeeded.map(g => g.name))
|
|
71
|
-
console.log('add failed: ', guidesAdded.failed)
|
|
72
|
-
|
|
73
|
-
console.log('\n--- integrity: annex referenced by guide cannot be removed ---')
|
|
74
|
-
const annexBlocked = bep.annexes.remove([anx1Id])
|
|
75
|
-
console.log('remove IFC Tutorial (blocked by guide.annexIds):', annexBlocked.failed)
|
|
76
|
-
|
|
77
|
-
// ─── Workflows ────────────────────────────────────────────────────────────────
|
|
78
|
-
|
|
79
|
-
// A workflow is a named process diagram stored as a FlowDiagram — a record of
|
|
80
|
-
// nodes and edges identified by stable string keys. Each node can be a start,
|
|
81
|
-
// end, process, or decision step. Process nodes reference an action and carry
|
|
82
|
-
// RACI role assignments (responsible, accountable, consulted, informed).
|
|
83
|
-
//
|
|
84
|
-
// Edges outgoing from process nodes must declare a triggerEventId — the event
|
|
85
|
-
// that causes the transition.
|
|
86
|
-
//
|
|
87
|
-
// All references inside the diagram — actionIds, roleIds, edge targets —
|
|
88
|
-
// are validated on add and on update. Any broken reference fails the whole item.
|
|
89
|
-
|
|
90
|
-
console.log('\n=== workflows ===')
|
|
91
|
-
|
|
92
|
-
const wfAdded = bep.workflows.add([
|
|
93
|
-
{
|
|
94
|
-
name: 'Model Coordination',
|
|
95
|
-
description: 'Weekly model coordination workflow',
|
|
96
|
-
diagram: {
|
|
97
|
-
direction: 'LR',
|
|
98
|
-
nodes: {
|
|
99
|
-
start: { type: 'start' },
|
|
100
|
-
update: { type: 'process', actionId: actionUpdateId, responsibleRoleIds: [roleManagerId] },
|
|
101
|
-
review: { type: 'process', actionId: actionReviewId, responsibleRoleIds: [roleManagerId], accountableRoleIds: [roleManagerId] },
|
|
102
|
-
issues: { type: 'process', actionId: actionIssuesId, responsibleRoleIds: [roleManagerId], consultedRoleIds: [roleManagerId] },
|
|
103
|
-
end: { type: 'end' },
|
|
104
|
-
},
|
|
105
|
-
edges: {
|
|
106
|
-
e1: { from: 'start', to: 'update' },
|
|
107
|
-
e2: { from: 'update', to: 'review', triggerEventId: 'done' },
|
|
108
|
-
e3: { from: 'review', to: 'issues', triggerEventId: 'done' },
|
|
109
|
-
e4: { from: 'issues', to: 'end', triggerEventId: 'done' },
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
// integrity failures on add —
|
|
114
|
-
{
|
|
115
|
-
name: 'Bad Action Ref',
|
|
116
|
-
diagram: { direction: 'LR', nodes: { n1: { type: 'process', actionId: 'ghost-action' } }, edges: {} },
|
|
117
|
-
}, // fails — action not found
|
|
118
|
-
{
|
|
119
|
-
name: 'Bad Role Ref',
|
|
120
|
-
diagram: { direction: 'LR', nodes: { n1: { type: 'process', responsibleRoleIds: ['GHOST'] } }, edges: {} },
|
|
121
|
-
}, // fails — role not found
|
|
122
|
-
{
|
|
123
|
-
name: 'Bad Edge Ref',
|
|
124
|
-
diagram: { direction: 'LR', nodes: { n1: { type: 'start' } }, edges: { e1: { from: 'n1', to: 'ghost-node' } } },
|
|
125
|
-
}, // fails — edge target not found
|
|
126
|
-
])
|
|
127
|
-
const wfCoordId = wfAdded.succeeded[0].id
|
|
128
|
-
console.log('add succeeded:', wfAdded.succeeded.map(w => w.name))
|
|
129
|
-
console.log('add failed: ', wfAdded.failed)
|
|
130
|
-
|
|
131
|
-
console.log('\n--- integrity: action referenced by workflow node cannot be removed ---')
|
|
132
|
-
const actionBlocked = bep.actions.remove([actionUpdateId])
|
|
133
|
-
console.log('remove "Update model" (blocked by workflow node):', actionBlocked.failed)
|
|
134
|
-
|
|
135
|
-
console.log('\n--- integrity: role referenced by workflow RACI cannot be removed ---')
|
|
136
|
-
const roleBlocked = bep.roles.remove([roleManagerId])
|
|
137
|
-
console.log('remove BIM Manager (blocked by workflow RACI):', roleBlocked.failed)
|
|
138
|
-
|
|
139
|
-
console.log('\n--- update: diagram refs are re-validated on patch ---')
|
|
140
|
-
const wfPatchFailed = bep.workflows.update([{
|
|
141
|
-
id: wfCoordId,
|
|
142
|
-
diagram: { direction: 'LR', nodes: { n1: { type: 'process', actionId: 'ghost-action' } }, edges: {} },
|
|
143
|
-
}])
|
|
144
|
-
console.log('update with ghost actionId failed:', wfPatchFailed.failed)
|
|
145
|
-
|
|
146
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
147
|
-
|
|
148
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
149
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/04-bim-uses.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --04 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: objectives, bimUses.
|
|
4
|
-
//
|
|
5
|
-
// BIM Uses answer the question "why are we using BIM on this project?".
|
|
6
|
-
// Each use case ties together the project objectives it serves, the phases
|
|
7
|
-
// it applies to, and the workflows that describe how it is carried out in practice.
|
|
8
|
-
//
|
|
9
|
-
// Objectives are the measurable targets — they exist independently and can be
|
|
10
|
-
// referenced by multiple BIM Uses. BIM Uses are the bridge between the strategic
|
|
11
|
-
// layer (what we want to achieve) and the operational layer (how we do it).
|
|
12
|
-
//
|
|
13
|
-
// Software traceability is derived from the workflow chain:
|
|
14
|
-
// BIMUse → workflowIds → diagram.nodes → actionId → action.softwareIds
|
|
15
|
-
|
|
16
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
17
|
-
import { Bep } from '../dist/index.js'
|
|
18
|
-
|
|
19
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
20
|
-
|
|
21
|
-
const wfCoordId = bep.workflows.list().find(w => w.name === 'Model Coordination')!.id
|
|
22
|
-
|
|
23
|
-
// ─── Objectives ───────────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
console.log('=== objectives ===')
|
|
26
|
-
|
|
27
|
-
const objectivesAdded = bep.objectives.add([
|
|
28
|
-
{ description: 'Reduce coordination errors by 30%' },
|
|
29
|
-
{ description: 'Achieve LOD 350 at construction phase' },
|
|
30
|
-
{ description: 'Reduce RFI count by 25% vs last project' },
|
|
31
|
-
])
|
|
32
|
-
const obj1Id = objectivesAdded.succeeded[0].id
|
|
33
|
-
const obj2Id = objectivesAdded.succeeded[1].id
|
|
34
|
-
console.log('add succeeded:', objectivesAdded.succeeded.map(o => o.description))
|
|
35
|
-
|
|
36
|
-
bep.objectives.update([
|
|
37
|
-
{ id: obj1Id, description: 'Reduce coordination errors by 30% using Revit clash detection' },
|
|
38
|
-
{ id: 'ghost-obj', description: 'Ghost' }, // fails
|
|
39
|
-
])
|
|
40
|
-
|
|
41
|
-
// ─── BIM Uses ─────────────────────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
console.log('\n=== bimUses ===')
|
|
44
|
-
|
|
45
|
-
const bimUsesAdded = bep.bimUses.add([
|
|
46
|
-
{
|
|
47
|
-
name: 'Model Coordination',
|
|
48
|
-
objectiveIds: [obj1Id],
|
|
49
|
-
workflowIds: [wfCoordId],
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: 'Design Authoring',
|
|
53
|
-
objectiveIds: [obj2Id],
|
|
54
|
-
},
|
|
55
|
-
// integrity failures —
|
|
56
|
-
{ name: 'Bad Objective', objectiveIds: ['ghost-obj'] }, // fails — objective not found
|
|
57
|
-
{ name: 'Bad Workflow', workflowIds: ['ghost-wf'] }, // fails — workflow not found
|
|
58
|
-
])
|
|
59
|
-
const buCoordId = bimUsesAdded.succeeded[0].id
|
|
60
|
-
console.log('add succeeded:', bimUsesAdded.succeeded.map(b => b.name))
|
|
61
|
-
console.log('add failed: ', bimUsesAdded.failed)
|
|
62
|
-
|
|
63
|
-
console.log('\n--- integrity: workflow referenced by bimUse cannot be removed ---')
|
|
64
|
-
const wfBlocked = bep.workflows.remove([wfCoordId])
|
|
65
|
-
console.log('remove workflow (blocked by bimUse.workflowIds):', wfBlocked.failed)
|
|
66
|
-
|
|
67
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
68
|
-
|
|
69
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
70
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/05-standards.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --05 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: standards.
|
|
4
|
-
//
|
|
5
|
-
// Standards are the normative documents embedded inside the .bep zip — the
|
|
6
|
-
// naming conventions, export guidelines, and BIM requirements that govern how
|
|
7
|
-
// the project must be executed. Each standard is a markdown file stored at an
|
|
8
|
-
// auto-generated path inside the zip.
|
|
9
|
-
//
|
|
10
|
-
// Unlike other entities, standards carry file content in addition to metadata.
|
|
11
|
-
// The add() call takes content as a markdown string; the core writes it to the
|
|
12
|
-
// zip and stores the path in the entity. getContent/setContent read and overwrite
|
|
13
|
-
// that file. remove() also deletes the .md file from the zip.
|
|
14
|
-
//
|
|
15
|
-
// This dual nature — entity record + embedded file — is what makes standards
|
|
16
|
-
// versionable: the history system snapshots the .md file alongside bep.json
|
|
17
|
-
// whenever it changes between commits.
|
|
18
|
-
|
|
19
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
20
|
-
import { Bep } from '../dist/index.js'
|
|
21
|
-
|
|
22
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
23
|
-
|
|
24
|
-
// ─── Standards ────────────────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
// add() auto-generates a UUID path for each standard and writes the markdown
|
|
27
|
-
// content to the zip immediately. The returned entity carries contentPath so
|
|
28
|
-
// callers can see where the file lives inside the archive.
|
|
29
|
-
const stdAdded = bep.standards.add([
|
|
30
|
-
{ name: 'Naming Convention', content: '# Naming Convention\nAll files must follow ISO 19650 naming.' },
|
|
31
|
-
{ name: 'IFC Export Guide', content: '# IFC Export Guide\nUse IFC4 Reference View profile.' },
|
|
32
|
-
{ name: 'BIM Requirements', content: '# BIM Requirements\nMinimum LOD per phase defined below.' },
|
|
33
|
-
])
|
|
34
|
-
const stdNamingId = stdAdded.succeeded[0].id
|
|
35
|
-
const stdIfcId = stdAdded.succeeded[1].id
|
|
36
|
-
const stdBimId = stdAdded.succeeded[2].id
|
|
37
|
-
console.log('add succeeded:', stdAdded.succeeded.map(s => s.name))
|
|
38
|
-
console.log('content paths:', stdAdded.succeeded.map(s => s.contentPath)) // uuid-based paths in zip
|
|
39
|
-
|
|
40
|
-
// getContent — reads the .md file from inside the zip
|
|
41
|
-
const namingContent = await bep.standards.getContent(stdNamingId)
|
|
42
|
-
console.log('\ngetContent (first 45 chars):', namingContent.slice(0, 45))
|
|
43
|
-
|
|
44
|
-
// setContent — overwrites the .md file in the zip; no append, caller owns the full string
|
|
45
|
-
bep.standards.setContent(stdNamingId, '# Naming Convention v2\nRevised rules after client review.')
|
|
46
|
-
const updated = await bep.standards.getContent(stdNamingId)
|
|
47
|
-
console.log('after setContent (first 45 chars):', updated.slice(0, 45))
|
|
48
|
-
|
|
49
|
-
// remove — also deletes the corresponding .md file from the zip
|
|
50
|
-
const stdRemoved = bep.standards.remove([stdIfcId, 'ghost-std'])
|
|
51
|
-
console.log('\nremove succeeded:', stdRemoved.succeeded)
|
|
52
|
-
console.log('remove failed: ', stdRemoved.failed)
|
|
53
|
-
|
|
54
|
-
console.log('standards remaining:', bep.standards.list().map(s => s.name))
|
|
55
|
-
// → ['Naming Convention', 'BIM Requirements']
|
|
56
|
-
|
|
57
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
58
|
-
|
|
59
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
60
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/06-schedule.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --06 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: phases, milestones, lbsNodes.
|
|
4
|
-
//
|
|
5
|
-
// The schedule section defines when information must be delivered and where
|
|
6
|
-
// in the project's spatial breakdown each deliverable belongs.
|
|
7
|
-
//
|
|
8
|
-
// Phases are the major stages of the project (Design, Construction, Handover).
|
|
9
|
-
// Milestones are the information exchange events within those phases — each one
|
|
10
|
-
// has a concrete date and is the target that deliverables and LOIN entries
|
|
11
|
-
// are anchored to.
|
|
12
|
-
//
|
|
13
|
-
// The LBS (Location Breakdown Structure) is a spatial tree of zones and
|
|
14
|
-
// locations. Deliverable naming codes are derived from it: a deliverable on
|
|
15
|
-
// floor P01 (child of block BLK) gets zone=BLK, location=P01 in its code.
|
|
16
|
-
|
|
17
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
18
|
-
import { Bep } from '../dist/index.js'
|
|
19
|
-
|
|
20
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
21
|
-
|
|
22
|
-
// ─── Phases ───────────────────────────────────────────────────────────────────
|
|
23
|
-
|
|
24
|
-
// Phases are the top-level time containers. They have no dates of their own;
|
|
25
|
-
// the dates belong to milestones. Phases exist to group milestones and to
|
|
26
|
-
// derive the phase label for each deliverable at render time.
|
|
27
|
-
|
|
28
|
-
console.log('=== phases ===')
|
|
29
|
-
|
|
30
|
-
const phasesAdded = bep.phases.add([
|
|
31
|
-
{ name: 'Design' },
|
|
32
|
-
{ name: 'Construction' },
|
|
33
|
-
{ name: 'Handover' },
|
|
34
|
-
])
|
|
35
|
-
const desId = phasesAdded.succeeded[0].id
|
|
36
|
-
const conId = phasesAdded.succeeded[1].id
|
|
37
|
-
const hanId = phasesAdded.succeeded[2].id
|
|
38
|
-
console.log('add succeeded:', phasesAdded.succeeded.map(p => p.name))
|
|
39
|
-
|
|
40
|
-
// ─── Milestones ───────────────────────────────────────────────────────────────
|
|
41
|
-
|
|
42
|
-
// Milestones are the information exchange events defined by ISO 19650 — the
|
|
43
|
-
// moments at which teams must deliver a specific set of files. Each milestone
|
|
44
|
-
// has a concrete date (ISO 8601) and belongs to a phase.
|
|
45
|
-
// Deliverables and LOIN entries reference milestones to declare when and at
|
|
46
|
-
// what level of development something must be ready.
|
|
47
|
-
|
|
48
|
-
console.log('\n=== milestones ===')
|
|
49
|
-
|
|
50
|
-
const milestonesAdded = bep.milestones.add([
|
|
51
|
-
{ name: 'Design Delivery', date: '2026-06-30', phaseId: desId },
|
|
52
|
-
{ name: 'Construction Delivery', date: '2027-03-31', phaseId: conId },
|
|
53
|
-
{ name: 'Handover Package', date: '2027-09-30', phaseId: hanId },
|
|
54
|
-
{ name: 'Ghost Phase', date: '2026-12-31', phaseId: 'ghost-phase' }, // fails — phase not found
|
|
55
|
-
])
|
|
56
|
-
const m1Id = milestonesAdded.succeeded[0].id
|
|
57
|
-
const m2Id = milestonesAdded.succeeded[1].id
|
|
58
|
-
console.log('add succeeded:', milestonesAdded.succeeded.map(m => m.name))
|
|
59
|
-
console.log('add failed: ', milestonesAdded.failed)
|
|
60
|
-
|
|
61
|
-
console.log('\n--- integrity: phase referenced by milestone cannot be removed ---')
|
|
62
|
-
const phaseBlocked = bep.phases.remove([desId])
|
|
63
|
-
console.log('remove Design (blocked by milestone.phaseId):', phaseBlocked.failed)
|
|
64
|
-
|
|
65
|
-
// ─── LBS Nodes ────────────────────────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
// The LBS (Location Breakdown Structure) is a spatial tree used to locate
|
|
68
|
-
// deliverables within the project. Each node is either a zone (container) or a
|
|
69
|
-
// location (leaf). The id is the naming code that appears in deliverable names.
|
|
70
|
-
//
|
|
71
|
-
// Build the tree bottom-up — leaves first — so that child references resolve
|
|
72
|
-
// on add. The root is the last node added; it is identified by having no parent.
|
|
73
|
-
//
|
|
74
|
-
// SIT (zone, root)
|
|
75
|
-
// ├─ BLK (zone)
|
|
76
|
-
// │ ├─ P01 (location)
|
|
77
|
-
// │ └─ P02 (location)
|
|
78
|
-
// └─ FAC (zone)
|
|
79
|
-
|
|
80
|
-
bep.lbsNodes.add([
|
|
81
|
-
{ id: 'P01', name: 'Floor 1', type: 'location' },
|
|
82
|
-
{ id: 'P02', name: 'Floor 2', type: 'location' },
|
|
83
|
-
{ id: 'FAC', name: 'Facade', type: 'zone' },
|
|
84
|
-
])
|
|
85
|
-
bep.lbsNodes.add([
|
|
86
|
-
{ id: 'BLK', name: 'Block A', type: 'zone', lbsNodeIds: ['P01', 'P02'] },
|
|
87
|
-
])
|
|
88
|
-
const lbsRoot = bep.lbsNodes.add([
|
|
89
|
-
{ id: 'SIT', name: 'Site', type: 'zone', lbsNodeIds: ['BLK', 'FAC'] },
|
|
90
|
-
])
|
|
91
|
-
console.log('add root:', lbsRoot.succeeded.map(n => n.id))
|
|
92
|
-
console.log('tree: ', bep.lbsNodes.list().map(n => `${n.id}(${n.type})`))
|
|
93
|
-
|
|
94
|
-
// validateTree: whole-tree structural check (roots must be zones, no cycles)
|
|
95
|
-
console.log('\nvalidateTree (valid tree):', bep.lbsNodes.validateTree()) // []
|
|
96
|
-
|
|
97
|
-
// resolveCodes: returns { zoneCode, locationCode } for deliverable naming
|
|
98
|
-
console.log('\n--- resolveCodes ---')
|
|
99
|
-
console.log('absent: ', bep.lbsNodes.resolveCodes(undefined)) // XXX/XXX — no LBS node provided
|
|
100
|
-
console.log('root SIT: ', bep.lbsNodes.resolveCodes('SIT')) // ZZZ/ZZZ — root has no zone parent
|
|
101
|
-
console.log('zone BLK:', bep.lbsNodes.resolveCodes('BLK')) // BLK/ZZZ
|
|
102
|
-
console.log('loc P01: ', bep.lbsNodes.resolveCodes('P01')) // BLK/P01
|
|
103
|
-
|
|
104
|
-
// per-node validation errors caught on add
|
|
105
|
-
console.log('\n--- add validation errors ---')
|
|
106
|
-
const badRef = bep.lbsNodes.add([{ id: 'BAD', name: 'Bad', type: 'zone', lbsNodeIds: ['ghost'] }])
|
|
107
|
-
console.log('missing child ref:', badRef.failed)
|
|
108
|
-
|
|
109
|
-
const badChild = bep.lbsNodes.add([{ id: 'BAD2', name: 'Bad', type: 'location', lbsNodeIds: ['FAC'] }])
|
|
110
|
-
console.log('location with zone child:', badChild.failed)
|
|
111
|
-
|
|
112
|
-
// validateTree catches structural errors not checked per-node (e.g. orphan location as root)
|
|
113
|
-
bep.lbsNodes.add([{ id: 'ORPHAN', name: 'Orphan', type: 'location' }])
|
|
114
|
-
console.log('\nvalidateTree (orphan location as root):', bep.lbsNodes.validateTree())
|
|
115
|
-
bep.lbsNodes.remove(['ORPHAN'])
|
|
116
|
-
|
|
117
|
-
console.log('\n--- integrity: node referenced as child cannot be removed ---')
|
|
118
|
-
const nodeBlocked = bep.lbsNodes.remove(['BLK'])
|
|
119
|
-
console.log('remove BLK (blocked by SIT.lbsNodeIds):', nodeBlocked.failed)
|
|
120
|
-
|
|
121
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
122
|
-
|
|
123
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
124
|
-
console.log('\nSaved → examples/example.bep')
|