@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.
- package/dist/index.d.ts +7 -5
- package/dist/index.js +604 -596
- 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/examples/12-history.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --12 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: history — commit, status, hasPendingChanges, discard, compare,
|
|
4
|
-
// get, getStandardContent, revert, reset, squash.
|
|
5
|
-
//
|
|
6
|
-
// The history system versions the BEP using inverse RFC 6902 diffs. Each
|
|
7
|
-
// commit stores how to go back to the previous version, so the current state
|
|
8
|
-
// is always bep.json and older states are reconstructed on demand.
|
|
9
|
-
//
|
|
10
|
-
// Version numbers follow a {major}.{minor} scheme:
|
|
11
|
-
// patch commit → bumps minor (0.0 → 0.1 → 0.2)
|
|
12
|
-
// version commit → bumps major (0.x → 1.0), requires approvedBy[]
|
|
13
|
-
//
|
|
14
|
-
// Bep.open() auto-normalizes a BEP with no history by silently creating a v0.0
|
|
15
|
-
// baseline from the current state. The first manual commit therefore lands at
|
|
16
|
-
// v0.1, not v0.0. This example operates in memory only — it does not write back
|
|
17
|
-
// to example.bep, so the history modifications are discarded after the run.
|
|
18
|
-
//
|
|
19
|
-
// Standards (.md files) are versioned separately from bep.json: the history
|
|
20
|
-
// system snapshots each .md file only when it changes between commits, and
|
|
21
|
-
// resolves the correct snapshot when getStandardContent(id, version) is called.
|
|
22
|
-
|
|
23
|
-
import { readFileSync } from 'node:fs'
|
|
24
|
-
import { Bep } from '../dist/index.js'
|
|
25
|
-
|
|
26
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
27
|
-
|
|
28
|
-
const stdNamingId = bep.standards.list().find(s => s.name === 'Naming Convention')!.id
|
|
29
|
-
|
|
30
|
-
// ─── v0.1: first manual commit ────────────────────────────────────────────────
|
|
31
|
-
//
|
|
32
|
-
// Bep.open() auto-normalizes a BEP without history by creating a v0.0 baseline
|
|
33
|
-
// from the current state. The first manual commit therefore lands at v0.1.
|
|
34
|
-
|
|
35
|
-
console.log('=== history ===')
|
|
36
|
-
console.log('\n--- commit v0.1 (initial) ---')
|
|
37
|
-
|
|
38
|
-
const v0 = await bep.history.commit({
|
|
39
|
-
type: 'patch',
|
|
40
|
-
author: 'alice@arc.com',
|
|
41
|
-
description: 'Initial BEP draft — all sections complete',
|
|
42
|
-
})
|
|
43
|
-
console.log('committed:', v0.version) // 0.1
|
|
44
|
-
|
|
45
|
-
// ─── v0.2: data changes + standard content update ─────────────────────────────
|
|
46
|
-
|
|
47
|
-
console.log('\n--- changes for v0.2 ---')
|
|
48
|
-
|
|
49
|
-
bep.roles.add([{ name: 'BIM Author', color: '#22CC88' }])
|
|
50
|
-
bep.standards.setContent(stdNamingId, '# Naming Convention v3\nRevised rules after client review.')
|
|
51
|
-
|
|
52
|
-
// status() reports what changed since the last commit
|
|
53
|
-
const st02 = await bep.history.status()
|
|
54
|
-
console.log('pending — standards:', st02.standards)
|
|
55
|
-
// → [{ status: 'content-modified', id: stdNamingId }]
|
|
56
|
-
|
|
57
|
-
const v1 = await bep.history.commit({
|
|
58
|
-
type: 'patch',
|
|
59
|
-
author: 'alice@arc.com',
|
|
60
|
-
description: 'Add BIM Author role + revise naming standard',
|
|
61
|
-
})
|
|
62
|
-
console.log('committed:', v1.version) // 0.2
|
|
63
|
-
|
|
64
|
-
// resolve standard content at specific historical versions
|
|
65
|
-
const namingAtV01 = await bep.history.getStandardContent(stdNamingId, '0.1')
|
|
66
|
-
const namingAtV02 = await bep.history.getStandardContent(stdNamingId, '0.2')
|
|
67
|
-
console.log('naming @ v0.1 (first 35):', namingAtV01?.slice(0, 35))
|
|
68
|
-
console.log('naming @ v0.2 (first 35):', namingAtV02?.slice(0, 35))
|
|
69
|
-
|
|
70
|
-
// ─── v1.0: official version with approvers ────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
console.log('\n--- commit v1.0 (official version, requires approvedBy) ---')
|
|
73
|
-
|
|
74
|
-
bep.standards.setContent(stdNamingId, '# Naming Convention v4\nFinal approved version.')
|
|
75
|
-
bep.phases.add([{ name: 'Tender' }])
|
|
76
|
-
|
|
77
|
-
const v2 = await bep.history.commit({
|
|
78
|
-
type: 'version',
|
|
79
|
-
author: 'alice@arc.com',
|
|
80
|
-
description: 'First official BEP release',
|
|
81
|
-
approvedBy: ['alice@arc.com'],
|
|
82
|
-
})
|
|
83
|
-
console.log('committed:', v2.version) // 1.0
|
|
84
|
-
|
|
85
|
-
// ─── discard ──────────────────────────────────────────────────────────────────
|
|
86
|
-
|
|
87
|
-
console.log('\n--- discard uncommitted changes ---')
|
|
88
|
-
|
|
89
|
-
bep.phases.add([{ name: 'Temporary — will be discarded' }])
|
|
90
|
-
bep.standards.setContent(stdNamingId, '# WILL BE DISCARDED')
|
|
91
|
-
|
|
92
|
-
console.log('hasPendingChanges before discard:', await bep.history.hasPendingChanges())
|
|
93
|
-
await bep.history.discard()
|
|
94
|
-
console.log('hasPendingChanges after discard: ', await bep.history.hasPendingChanges())
|
|
95
|
-
|
|
96
|
-
const namingAfterDiscard = await bep.standards.getContent(stdNamingId)
|
|
97
|
-
console.log('naming std restored (first 35):', namingAfterDiscard.slice(0, 35))
|
|
98
|
-
// → v4 content (restored from baseline at v1.0)
|
|
99
|
-
|
|
100
|
-
// ─── list / get / compare ─────────────────────────────────────────────────────
|
|
101
|
-
|
|
102
|
-
console.log('\n--- list / get / compare ---')
|
|
103
|
-
|
|
104
|
-
const versions = await bep.history.list()
|
|
105
|
-
console.log('versions:', versions.map(v => v.version)) // ['0.1', '0.2', '1.0']
|
|
106
|
-
|
|
107
|
-
// get: reconstruct state at v0.1 — BIM Author role should not exist yet
|
|
108
|
-
const atV01 = await bep.history.get('0.1')
|
|
109
|
-
const bimAuthorInV01 = atV01.roles.find(r => r.name === 'BIM Author')
|
|
110
|
-
console.log('BIM Author in v0.1:', bimAuthorInV01 ?? 'not found (correct)')
|
|
111
|
-
|
|
112
|
-
// compare: RFC 6902 diff between two versions + standards diff
|
|
113
|
-
const { diff: ops, standards: stdDiff } = await bep.history.compare('0.1', '0.2')
|
|
114
|
-
console.log('ops v0.1→v0.2:', ops.length, 'operation(s)', ops.slice(0, 2).map(o => `${o.op} ${o.path}`))
|
|
115
|
-
console.log('std diff: ', stdDiff)
|
|
116
|
-
|
|
117
|
-
// ─── revert ───────────────────────────────────────────────────────────────────
|
|
118
|
-
|
|
119
|
-
console.log('\n--- revert to v0.0 (non-destructive — creates a new version) ---')
|
|
120
|
-
|
|
121
|
-
const v3 = await bep.history.revert('0.1', {
|
|
122
|
-
type: 'patch',
|
|
123
|
-
author: 'alice@arc.com',
|
|
124
|
-
description: 'Revert to initial draft',
|
|
125
|
-
})
|
|
126
|
-
console.log('reverted as:', v3.version) // 1.1
|
|
127
|
-
|
|
128
|
-
const bimAuthorAfterRevert = bep.roles.list().find(r => r.name === 'BIM Author')
|
|
129
|
-
console.log('BIM Author after revert:', bimAuthorAfterRevert ?? 'not found (correct)')
|
|
130
|
-
console.log('versions after revert: ', (await bep.history.list()).map(v => v.version))
|
|
131
|
-
// → ['0.0', '0.1', '0.2', '1.0', '1.1']
|
|
132
|
-
|
|
133
|
-
// ─── reset ────────────────────────────────────────────────────────────────────
|
|
134
|
-
|
|
135
|
-
console.log('\n--- reset to v0.2 (destructive — deletes all versions after v0.2) ---')
|
|
136
|
-
|
|
137
|
-
console.log('versions before reset:', (await bep.history.list()).map(v => v.version))
|
|
138
|
-
await bep.history.reset('0.2')
|
|
139
|
-
console.log('versions after reset: ', (await bep.history.list()).map(v => v.version))
|
|
140
|
-
// → ['0.0', '0.1', '0.2']
|
|
141
|
-
|
|
142
|
-
// ─── squash ───────────────────────────────────────────────────────────────────
|
|
143
|
-
|
|
144
|
-
console.log('\n--- squash (destructive — collapses all history into one terminus) ---')
|
|
145
|
-
|
|
146
|
-
console.log('versions before squash:', (await bep.history.list()).map(v => v.version))
|
|
147
|
-
|
|
148
|
-
const squashed = await bep.history.squash({
|
|
149
|
-
newBase: '2.0',
|
|
150
|
-
author: 'alice@arc.com',
|
|
151
|
-
description: 'Clean start — squash all history into v2.0',
|
|
152
|
-
approvedBy: ['alice@arc.com'],
|
|
153
|
-
})
|
|
154
|
-
console.log('squash result:', squashed.version)
|
|
155
|
-
console.log('versions after squash:', (await bep.history.list()).map(v => v.version))
|
|
156
|
-
// → ['2.0']
|
|
157
|
-
|
|
158
|
-
// getStandardContent still works from the new terminus
|
|
159
|
-
const namingAt20 = await bep.history.getStandardContent(stdNamingId, '2.0')
|
|
160
|
-
console.log('\nnaming std @ 2.0 (first 35):', namingAt20?.slice(0, 35))
|
|
161
|
-
|
|
162
|
-
// get() terminus works
|
|
163
|
-
const atSquashed = await bep.history.get('2.0')
|
|
164
|
-
console.log('get 2.0 — project name:', atSquashed.project.name)
|
|
165
|
-
|
|
166
|
-
console.log('\nDone.')
|
package/examples/13-engine.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
// run: node --experimental-strip-types examples/13-engine.ts (from core/)
|
|
2
|
-
//
|
|
3
|
-
// Covers: Engine, Runtime, workflow execution, type generation,
|
|
4
|
-
// getRemoteData, useAdapter.
|
|
5
|
-
//
|
|
6
|
-
// bep.generateRuntimeTypes() produces a TypeScript contract from the BEP's runtime handlers — with JSDoc from each description field.
|
|
7
|
-
// Writing it to bep.d.ts gives full type safety in the Runtime development.
|
|
8
|
-
//
|
|
9
|
-
// Workflow (3 nodes):
|
|
10
|
-
//
|
|
11
|
-
// start ──► review ──[submit / effect: notify-reviewer]──► end
|
|
12
|
-
|
|
13
|
-
import { writeFileSync } from 'node:fs'
|
|
14
|
-
import * as BEP from '../dist/index.js'
|
|
15
|
-
import type { BepTypes } from './bep.js'
|
|
16
|
-
|
|
17
|
-
// ─── 1. Build the BEP ─────────────────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
const bep = BEP.Bep.create({ name: 'Demo Project', code: 'DEMO', description: '' })
|
|
20
|
-
|
|
21
|
-
const [{ id: roleManagerId }] = bep.roles.add([{ name: 'BIM Manager' }]).succeeded
|
|
22
|
-
bep.members.add([{ email: 'manager@demo.com', name: 'Ana García', roleId: roleManagerId }])
|
|
23
|
-
const [{ id: assetTypeId }] = bep.assetTypes.add([{ id: 'MDL', name: 'Model' }]).succeeded
|
|
24
|
-
const [{ id: actionReviewId }] = bep.actions.add([{ name: 'Review model' }]).succeeded
|
|
25
|
-
|
|
26
|
-
bep.events.add([
|
|
27
|
-
{ id: 'submit', name: 'Submit for review', payload: [{ key: 'comment', type: 'string', required: false }] },
|
|
28
|
-
{ id: 'approved', name: 'Approved' },
|
|
29
|
-
])
|
|
30
|
-
bep.effects.add([
|
|
31
|
-
{
|
|
32
|
-
id: 'notify-reviewer', name: 'Notify reviewer',
|
|
33
|
-
description: 'Sends a notification to the assigned reviewer when a model is submitted. Uses the comment from the submit event payload.',
|
|
34
|
-
payload: [{ key: 'comment', type: 'string', required: false }],
|
|
35
|
-
},
|
|
36
|
-
])
|
|
37
|
-
bep.automations.add([
|
|
38
|
-
{
|
|
39
|
-
id: 'auto-approve', name: 'Auto approve',
|
|
40
|
-
description: 'Automatically approves the model if no blocking issues are found in the previous review cycle.',
|
|
41
|
-
payload: [{ key: 'threshold', type: 'number', required: true }],
|
|
42
|
-
output: [{ key: 'result', type: 'string', required: true }],
|
|
43
|
-
},
|
|
44
|
-
])
|
|
45
|
-
bep.resolvers.add([
|
|
46
|
-
{
|
|
47
|
-
id: 'fetch-json', name: 'Fetch JSON',
|
|
48
|
-
description: 'Fetches a JSON array from the remote data URL. Authenticates with an API key via Authorization header. Returns the raw parsed array.',
|
|
49
|
-
envKeys: ['API_KEY'],
|
|
50
|
-
},
|
|
51
|
-
])
|
|
52
|
-
bep.adapters.add([
|
|
53
|
-
{
|
|
54
|
-
id: 'pick-label-value', name: 'Pick label + value',
|
|
55
|
-
description: 'Maps an array of { name, count } objects to { label, value } pairs compatible with dotbep:pie-chart.',
|
|
56
|
-
},
|
|
57
|
-
])
|
|
58
|
-
bep.remoteData.add([
|
|
59
|
-
{
|
|
60
|
-
name: 'Model stats', url: 'https://example.com/stats.json',
|
|
61
|
-
description: 'Aggregated model statistics exported nightly from the project management tool.',
|
|
62
|
-
resolverId: 'fetch-json',
|
|
63
|
-
},
|
|
64
|
-
])
|
|
65
|
-
|
|
66
|
-
const [{ id: workflowId }] = bep.workflows.add([{
|
|
67
|
-
name: 'Model Review',
|
|
68
|
-
diagram: {
|
|
69
|
-
direction: 'LR',
|
|
70
|
-
nodes: {
|
|
71
|
-
start: { type: 'start' },
|
|
72
|
-
review: { type: 'process', actionId: actionReviewId, responsibleRoleIds: [roleManagerId] },
|
|
73
|
-
end: { type: 'end' },
|
|
74
|
-
},
|
|
75
|
-
edges: {
|
|
76
|
-
e1: { from: 'start', to: 'review' },
|
|
77
|
-
e2: { from: 'review', to: 'end', triggerEventId: 'submit', effectIds: ['notify-reviewer'] },
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
}]).succeeded
|
|
81
|
-
|
|
82
|
-
// ─── 2. Generate types ────────────────────────────────────────────────────────
|
|
83
|
-
//
|
|
84
|
-
// bep.generateRuntimeTypes() produces a TypeScript contract from the BEP's effects and
|
|
85
|
-
// automations. Commit bep.d.ts alongside your runtime so TypeScript can validate it.
|
|
86
|
-
|
|
87
|
-
writeFileSync('examples/bep.d.ts', bep.generateRuntimeTypes())
|
|
88
|
-
console.log('Generated examples/bep.d.ts')
|
|
89
|
-
|
|
90
|
-
// ─── 3. Declare the BEP Runtime ───────────────────────────────────────────────
|
|
91
|
-
//
|
|
92
|
-
// BepTypes (from bep.d.ts) types each handler's payload automatically.
|
|
93
|
-
|
|
94
|
-
class MyRuntime extends BEP.Runtime<BepTypes> {
|
|
95
|
-
constructor(options: BEP.RuntimeOptions) {
|
|
96
|
-
super(options)
|
|
97
|
-
this.effect('notify-reviewer', async (instance, payload) => {
|
|
98
|
-
console.log(' [effect] notify-reviewer fired')
|
|
99
|
-
console.log(' [effect] submitted by:', instance.history.at(-1)?.actor)
|
|
100
|
-
console.log(' [effect] comment:', payload.comment) // string | undefined ← inferred
|
|
101
|
-
})
|
|
102
|
-
this.automation('auto-approve', async (_instance, payload) => {
|
|
103
|
-
console.log(' [automation] auto-approve running, threshold:', payload.threshold)
|
|
104
|
-
return { eventId: 'approved', result: 'passed' }
|
|
105
|
-
})
|
|
106
|
-
this.resolver('fetch-json', async (url, env) => {
|
|
107
|
-
const res = await fetch(url, { headers: { Authorization: `Bearer ${env.API_KEY}` } })
|
|
108
|
-
return res.json()
|
|
109
|
-
})
|
|
110
|
-
this.adapter('pick-label-value', (data) => {
|
|
111
|
-
return (data as { name: string; count: number }[]).map(d => ({ label: d.name, value: d.count }))
|
|
112
|
-
})
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// ─── 4. Init the engine and run ───────────────────────────────────────────────
|
|
117
|
-
|
|
118
|
-
bep.engine.init({ runtime: new MyRuntime({ env: {} }) })
|
|
119
|
-
|
|
120
|
-
console.log('\n=== create instance ===')
|
|
121
|
-
const instance = await bep.engine.createInstance(
|
|
122
|
-
workflowId,
|
|
123
|
-
{ assetTypeId, id: 'model-001', label: 'Structural Model v3', source: 'bep:deliverables' },
|
|
124
|
-
'manager@demo.com',
|
|
125
|
-
)
|
|
126
|
-
console.log('status:', instance!.status)
|
|
127
|
-
console.log('current node:', instance!.currentNodeId)
|
|
128
|
-
|
|
129
|
-
console.log('\n=== emit: submit ===')
|
|
130
|
-
const result = await bep.engine.emit(instance!.id, {
|
|
131
|
-
eventId: 'submit',
|
|
132
|
-
actor: 'manager@demo.com',
|
|
133
|
-
payload: { comment: 'Ready for review' },
|
|
134
|
-
})
|
|
135
|
-
console.log('ok:', result.ok)
|
|
136
|
-
console.log('transitions:', result.transitionsApplied?.map(t => `${t.fromNodeId} → ${t.toNodeId}`))
|
|
137
|
-
console.log('effects:', result.effects?.map(e => `${e.effectId}: ${e.status}`))
|
|
138
|
-
console.log('final node:', result.instance?.currentNodeId)
|
|
139
|
-
console.log('final status:', result.instance?.status)
|
|
140
|
-
|
|
141
|
-
console.log('\n=== getRemoteData + useAdapter ===')
|
|
142
|
-
// Uses a mock resolver so the demo works without a real endpoint.
|
|
143
|
-
const remoteDataId = bep.data.remoteData[0]!.id
|
|
144
|
-
try {
|
|
145
|
-
const raw = await bep.engine.getRemoteData(remoteDataId)
|
|
146
|
-
const adapted = bep.engine.useAdapter('pick-label-value', raw)
|
|
147
|
-
console.log('raw data:', raw)
|
|
148
|
-
console.log('adapted:', adapted)
|
|
149
|
-
} catch (err) {
|
|
150
|
-
// example.com/stats.json returns HTML — expected in this demo.
|
|
151
|
-
console.log('(resolver error, expected with placeholder URL):', (err as Error).message)
|
|
152
|
-
}
|
package/examples/bep.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Generated by bep.generateTypes() — do not edit manually
|
|
2
|
-
|
|
3
|
-
// ─── Effects ──────────────────────────────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
export interface BepEffects {
|
|
6
|
-
/** Sends a notification to the assigned reviewer when a model is submitted. Uses the comment from the submit event payload. */
|
|
7
|
-
'notify-reviewer': (payload: { comment?: string }) => void
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// ─── Automations ─────────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
export interface BepAutomations {
|
|
13
|
-
/** Automatically approves the model if no blocking issues are found in the previous review cycle. */
|
|
14
|
-
'auto-approve': (payload: { threshold: number }) => { eventId: string; result: string }
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// ─── Resolvers ────────────────────────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
export interface BepResolvers {
|
|
20
|
-
/** Fetches a JSON array from the remote data URL. Authenticates with an API key via Authorization header. Returns the raw parsed array. */
|
|
21
|
-
'fetch-json': (url: string, env: { API_KEY: string }) => unknown
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// ─── Adapters ─────────────────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
export interface BepAdapters {
|
|
27
|
-
/** Maps an array of { name, count } objects to { label, value } pairs compatible with dotbep:pie-chart. */
|
|
28
|
-
'pick-label-value': (data: unknown) => unknown
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// ─── Combined ─────────────────────────────────────────────────────────────────
|
|
32
|
-
|
|
33
|
-
export interface BepTypes {
|
|
34
|
-
effects: BepEffects
|
|
35
|
-
automations: BepAutomations
|
|
36
|
-
resolvers: BepResolvers
|
|
37
|
-
adapters: BepAdapters
|
|
38
|
-
}
|
package/examples/example.bep
DELETED
|
Binary file
|
package/examples/run-all.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// run: node --experimental-strip-types examples/run-all.ts (from core/)
|
|
2
|
-
// Runs all examples in sequence. Each example builds on the .bep saved by the previous one.
|
|
3
|
-
// Optional: --NN runs only examples 01 through NN (e.g. --05 stops after 05-standards).
|
|
4
|
-
import { execSync } from 'node:child_process'
|
|
5
|
-
|
|
6
|
-
const examples = [
|
|
7
|
-
'01-participants',
|
|
8
|
-
'02-files',
|
|
9
|
-
'03-workflows',
|
|
10
|
-
'04-bim-uses',
|
|
11
|
-
'05-standards',
|
|
12
|
-
'06-schedule',
|
|
13
|
-
'07-loin',
|
|
14
|
-
'08-deliverables',
|
|
15
|
-
'09-notes',
|
|
16
|
-
'10-llm',
|
|
17
|
-
'11-resolved',
|
|
18
|
-
'12-history',
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
const untilArg = process.argv.find(a => /^--\d{2}$/.test(a))
|
|
22
|
-
const untilPrefix = untilArg ? untilArg.slice(2) : null
|
|
23
|
-
const toRun = untilPrefix ? examples.filter(e => e.slice(0, 2) <= untilPrefix) : examples
|
|
24
|
-
|
|
25
|
-
for (const ex of toRun) {
|
|
26
|
-
console.log(`\n${'─'.repeat(60)}`)
|
|
27
|
-
console.log(` examples/${ex}.ts`)
|
|
28
|
-
console.log('─'.repeat(60))
|
|
29
|
-
execSync(`node --experimental-strip-types examples/${ex}.ts`, {
|
|
30
|
-
stdio: 'inherit',
|
|
31
|
-
cwd: process.cwd(),
|
|
32
|
-
env: { ...process.env, DOTBEP_RUN_ALL: '1' },
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log(`\n${'─'.repeat(60)}`)
|
|
37
|
-
console.log(untilPrefix ? ` Done (up to ${untilPrefix}).` : ' All examples completed.')
|
|
38
|
-
console.log('─'.repeat(60))
|
package/src/base/entity.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { z, ZodError } from 'zod'
|
|
2
|
-
import type { BEP } from '../types/schema.js'
|
|
3
|
-
import { type ArrayKeys, checkRefs, checkOutgoingRefs } from '../utils/integrity.js'
|
|
4
|
-
|
|
5
|
-
function errMsg(e: unknown): string {
|
|
6
|
-
if (e instanceof ZodError)
|
|
7
|
-
return e.issues.map(i => (i.path.length ? i.path.join('.') + ': ' : '') + i.message).join('; ')
|
|
8
|
-
return (e as Error).message
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type BulkResult<T> = {
|
|
12
|
-
succeeded: T[]
|
|
13
|
-
failed: { id: string; error: string }[]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Input type for add() on non-autoId entities — id is optional, validated by the Zod schema */
|
|
17
|
-
export type AddInput<T extends object> = Omit<T, 'id'> & { id?: string }
|
|
18
|
-
|
|
19
|
-
export type EntityConfig<T extends object, AutoId extends boolean = false> = {
|
|
20
|
-
/** Key of this entity's array in BEP — used for automatic referential integrity checks */
|
|
21
|
-
key: ArrayKeys<BEP>
|
|
22
|
-
/** Field used as the unique identifier. Defaults to 'id' */
|
|
23
|
-
idField?: keyof T
|
|
24
|
-
/** Zod schema for this entity — used to validate input on add and merged result on update */
|
|
25
|
-
schema: z.ZodType<T>
|
|
26
|
-
/**
|
|
27
|
-
* When true, a UUID is auto-generated for the id field.
|
|
28
|
-
* add() will not accept an id in its input — callers capture it from the result.
|
|
29
|
-
* Use for entities whose id is opaque (not part of nomenclature and not user-facing).
|
|
30
|
-
*/
|
|
31
|
-
autoId?: AutoId
|
|
32
|
-
/**
|
|
33
|
-
* Custom validation called after schema parse (on add) and after merge (on update).
|
|
34
|
-
* Use for nested reference checks not covered by the standard integrity rules.
|
|
35
|
-
* Returns a list of error messages; empty array means valid.
|
|
36
|
-
*/
|
|
37
|
-
validate?: (item: T, bep: BEP) => string[]
|
|
38
|
-
/** Called before removing an entity, after ref checks pass. Use for custom logic not covered by integrity rules. */
|
|
39
|
-
beforeRemove?: (id: string, bep: BEP) => void
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export class Entity<T extends object, AutoId extends boolean = false> {
|
|
43
|
-
private idField: keyof T
|
|
44
|
-
|
|
45
|
-
constructor(
|
|
46
|
-
private getItems: () => T[],
|
|
47
|
-
protected getBep: () => BEP,
|
|
48
|
-
private config: EntityConfig<T, AutoId>,
|
|
49
|
-
) {
|
|
50
|
-
this.idField = config.idField ?? ('id' as keyof T)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private getId(entity: T): string {
|
|
54
|
-
return String(entity[this.idField])
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
list(): T[] {
|
|
58
|
-
return this.getItems()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
get(ids: string[]): BulkResult<T> {
|
|
62
|
-
const succeeded: T[] = []
|
|
63
|
-
const failed: { id: string; error: string }[] = []
|
|
64
|
-
for (const id of ids) {
|
|
65
|
-
const entity = this.getItems().find(e => this.getId(e) === id)
|
|
66
|
-
if (entity) succeeded.push(entity)
|
|
67
|
-
else failed.push({ id, error: `Not found: ${id}` })
|
|
68
|
-
}
|
|
69
|
-
return { succeeded, failed }
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
add(inputs: (AutoId extends true ? Omit<T, 'id'> : AddInput<T>)[]): BulkResult<T> {
|
|
73
|
-
const succeeded: T[] = []
|
|
74
|
-
const failed: { id: string; error: string }[] = []
|
|
75
|
-
for (const input of inputs) {
|
|
76
|
-
const raw = { ...input } as Record<string, unknown>
|
|
77
|
-
if (this.config.autoId && !raw[this.idField as string])
|
|
78
|
-
raw[this.idField as string] = globalThis.crypto.randomUUID()
|
|
79
|
-
const id = String(raw[this.idField as string] ?? '(unknown)')
|
|
80
|
-
try {
|
|
81
|
-
const entity = this.config.schema.parse(raw)
|
|
82
|
-
if (this.getItems().some(e => this.getId(e) === this.getId(entity)))
|
|
83
|
-
throw new Error(`Already exists: ${this.getId(entity)}`)
|
|
84
|
-
const outgoing = checkOutgoingRefs(entity as Record<string, unknown>, this.config.key, this.getBep())
|
|
85
|
-
if (outgoing.length) throw new Error(outgoing.join('; '))
|
|
86
|
-
const custom = this.config.validate?.(entity, this.getBep()) ?? []
|
|
87
|
-
if (custom.length) throw new Error(custom.join('; '))
|
|
88
|
-
this.getItems().push(entity)
|
|
89
|
-
succeeded.push(entity)
|
|
90
|
-
} catch (e) {
|
|
91
|
-
failed.push({ id, error: errMsg(e) })
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return { succeeded, failed }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
update(patches: ({ [K in keyof T]?: T[K] } & Record<string, unknown>)[]): BulkResult<T> {
|
|
98
|
-
const succeeded: T[] = []
|
|
99
|
-
const failed: { id: string; error: string }[] = []
|
|
100
|
-
for (const patch of patches) {
|
|
101
|
-
const id = String(patch[this.idField as string])
|
|
102
|
-
const items = this.getItems()
|
|
103
|
-
const index = items.findIndex(e => this.getId(e) === id)
|
|
104
|
-
if (index === -1) {
|
|
105
|
-
failed.push({ id, error: `Not found: ${id}` })
|
|
106
|
-
continue
|
|
107
|
-
}
|
|
108
|
-
const outgoing = checkOutgoingRefs(patch as Record<string, unknown>, this.config.key, this.getBep())
|
|
109
|
-
if (outgoing.length) {
|
|
110
|
-
failed.push({ id, error: outgoing.join('; ') })
|
|
111
|
-
continue
|
|
112
|
-
}
|
|
113
|
-
try {
|
|
114
|
-
const merged = this.config.schema.parse({ ...items[index], ...patch })
|
|
115
|
-
const custom = this.config.validate?.(merged, this.getBep()) ?? []
|
|
116
|
-
if (custom.length) throw new Error(custom.join('; '))
|
|
117
|
-
items[index] = merged
|
|
118
|
-
succeeded.push(items[index])
|
|
119
|
-
} catch (e) {
|
|
120
|
-
failed.push({ id, error: errMsg(e) })
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return { succeeded, failed }
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
remove(ids: string[]): BulkResult<string> {
|
|
127
|
-
const succeeded: string[] = []
|
|
128
|
-
const failed: { id: string; error: string }[] = []
|
|
129
|
-
for (const id of ids) {
|
|
130
|
-
const items = this.getItems()
|
|
131
|
-
const index = items.findIndex(e => this.getId(e) === id)
|
|
132
|
-
if (index === -1) {
|
|
133
|
-
failed.push({ id, error: `Not found: ${id}` })
|
|
134
|
-
continue
|
|
135
|
-
}
|
|
136
|
-
try {
|
|
137
|
-
const active = checkRefs(id, this.config.key, this.getBep())
|
|
138
|
-
if (active.length) throw new Error(`Referenced by: ${active.join(', ')}`)
|
|
139
|
-
this.config.beforeRemove?.(id, this.getBep())
|
|
140
|
-
items.splice(index, 1)
|
|
141
|
-
succeeded.push(id)
|
|
142
|
-
} catch (e) {
|
|
143
|
-
failed.push({ id, error: errMsg(e) })
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return { succeeded, failed }
|
|
147
|
-
}
|
|
148
|
-
}
|