@phosphorco/bb-identity 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/README.md +465 -0
- package/bb.d.ts +138 -0
- package/client.d.ts +175 -0
- package/dist/bb-entry-runtime.js +2574 -0
- package/dist/client-entry-runtime.js +2705 -0
- package/dist/host-runtime.js +932 -0
- package/dist/index-runtime.js +201 -0
- package/dist/model-runtime.js +207 -0
- package/dist/react-entry-runtime.js +3324 -0
- package/dist/server-runtime.js +263 -0
- package/dist/state-controller-runtime.js +950 -0
- package/dist/state-runtime.js +1200 -0
- package/dist/state-service-runtime.js +380 -0
- package/dist/state-transport-runtime.js +349 -0
- package/dist/testing-runtime.js +4084 -0
- package/host.d.ts +277 -0
- package/index.d.ts +3 -0
- package/model.d.ts +231 -0
- package/package.json +110 -0
- package/react.d.ts +129 -0
- package/server.d.ts +80 -0
- package/state.d.ts +170 -0
- package/testing.d.ts +202 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// model-runtime.ts
|
|
3
|
+
var ID_MAX_LENGTH = 256;
|
|
4
|
+
var ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@/-]*$/;
|
|
5
|
+
function failure(code, message, retry = "never") {
|
|
6
|
+
return { code, message, retry };
|
|
7
|
+
}
|
|
8
|
+
function ok(value) {
|
|
9
|
+
return { ok: true, value };
|
|
10
|
+
}
|
|
11
|
+
function err(code, message, retry = "never") {
|
|
12
|
+
return { ok: false, error: failure(code, message, retry) };
|
|
13
|
+
}
|
|
14
|
+
function isRecord(value) {
|
|
15
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
function isBoundedString(value, maximum = ID_MAX_LENGTH) {
|
|
18
|
+
return typeof value === "string" && value.length > 0 && value.length <= maximum;
|
|
19
|
+
}
|
|
20
|
+
function idCodec(kind) {
|
|
21
|
+
return {
|
|
22
|
+
decode(input) {
|
|
23
|
+
const valid = kind === "server-session" ? isBoundedString(input, 4096) && !/[\u0000-\u0020\u007f]/.test(input) : isBoundedString(input) && ID_PATTERN.test(input);
|
|
24
|
+
if (!valid) {
|
|
25
|
+
return err("invalid-input", `Invalid ${kind} identifier.`);
|
|
26
|
+
}
|
|
27
|
+
return ok(input);
|
|
28
|
+
},
|
|
29
|
+
encode(value) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var identityKeyCodec = {
|
|
35
|
+
decode(input) {
|
|
36
|
+
if (!isBoundedString(input, 512) || /[\u0000-\u001f\u007f]/.test(input)) {
|
|
37
|
+
return err("invalid-input", "Invalid identity key.");
|
|
38
|
+
}
|
|
39
|
+
return ok(input);
|
|
40
|
+
},
|
|
41
|
+
encode(value) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
function decodePresentation(value) {
|
|
46
|
+
return isRecord(value) && isBoundedString(value.displayName, 512) && (value.handle === null || isBoundedString(value.handle, 512)) && (value.avatarUrl === null || isBoundedString(value.avatarUrl, 2048));
|
|
47
|
+
}
|
|
48
|
+
function decodeIdentity(value) {
|
|
49
|
+
if (!isRecord(value) || !identityKeyCodec.decode(value.key).ok)
|
|
50
|
+
return false;
|
|
51
|
+
if (value.kind === "person")
|
|
52
|
+
return isBoundedString(value.issuer, 512) && isBoundedString(value.subject, 512);
|
|
53
|
+
if (value.kind === "default-user")
|
|
54
|
+
return isBoundedString(value.instanceId);
|
|
55
|
+
if (value.kind === "machine") {
|
|
56
|
+
return isBoundedString(value.instanceId) && (value.hostId === null || isBoundedString(value.hostId, 512));
|
|
57
|
+
}
|
|
58
|
+
return value.kind === "external" && isBoundedString(value.pluginId) && isBoundedString(value.subject, 512);
|
|
59
|
+
}
|
|
60
|
+
var profileCodec = {
|
|
61
|
+
decode(input) {
|
|
62
|
+
if (!isRecord(input) || !decodeIdentity(input.identity) || !decodePresentation(input.presentation) || !isBoundedString(input.revision) || input.status !== "current" && input.status !== "historical") {
|
|
63
|
+
return err("invalid-input", "Invalid identity profile.");
|
|
64
|
+
}
|
|
65
|
+
return ok(input);
|
|
66
|
+
},
|
|
67
|
+
encode(value) {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
function isContributionReference(value) {
|
|
72
|
+
return isRecord(value) && idCodec("thread").decode(value.threadId).ok && idCodec("contribution").decode(value.contributionId).ok;
|
|
73
|
+
}
|
|
74
|
+
function isPersonReference(value) {
|
|
75
|
+
return isRecord(value) && (value.kind === "person" || value.kind === "default-user") && decodeIdentity(value);
|
|
76
|
+
}
|
|
77
|
+
function isMachineReference(value) {
|
|
78
|
+
return isRecord(value) && value.kind === "machine" && decodeIdentity(value);
|
|
79
|
+
}
|
|
80
|
+
function isActorSnapshot(value) {
|
|
81
|
+
if (!isRecord(value) || !decodeIdentity(value.identity) || !decodePresentation(value.presentation))
|
|
82
|
+
return false;
|
|
83
|
+
const evidence = value.evidence;
|
|
84
|
+
if (evidence !== "provider-verified" && evidence !== "local-user" && evidence !== "upstream-default" && evidence !== "integration-asserted" && evidence !== "legacy" && evidence !== "machine")
|
|
85
|
+
return false;
|
|
86
|
+
return isMachineReference(value.identity) ? evidence === "machine" : evidence !== "machine";
|
|
87
|
+
}
|
|
88
|
+
function isOrigin(value) {
|
|
89
|
+
if (!isRecord(value))
|
|
90
|
+
return false;
|
|
91
|
+
if (value.kind === "person") {
|
|
92
|
+
const actor = value.actor;
|
|
93
|
+
return isActorSnapshot(actor) && isRecord(actor) && isPersonReference(actor.identity);
|
|
94
|
+
}
|
|
95
|
+
if (value.kind === "machine") {
|
|
96
|
+
const actor = value.actor;
|
|
97
|
+
return isActorSnapshot(actor) && isRecord(actor) && isMachineReference(actor.identity) && isRecord(actor) && actor.evidence === "machine";
|
|
98
|
+
}
|
|
99
|
+
if (value.kind === "external") {
|
|
100
|
+
const actor = value.actor;
|
|
101
|
+
return isActorSnapshot(actor) && isRecord(actor) && isRecord(actor.identity) && actor.identity.kind === "external" && actor.evidence !== "machine";
|
|
102
|
+
}
|
|
103
|
+
if (value.kind === "agent")
|
|
104
|
+
return value.agentId === null || isBoundedString(value.agentId);
|
|
105
|
+
if (value.kind === "system")
|
|
106
|
+
return isBoundedString(value.reason, 1024);
|
|
107
|
+
return value.kind === "unknown" && (value.reason === "legacy" || value.reason === "upstream-unattributed" || value.reason === "missing-source");
|
|
108
|
+
}
|
|
109
|
+
function isContribution(value) {
|
|
110
|
+
return isRecord(value) && isContributionReference(value.reference) && isOrigin(value.author) && (value.latestEditor === null || isActorSnapshot(value.latestEditor)) && isBoundedString(value.acceptedAt, 256) && Array.isArray(value.mentionedPeople) && value.mentionedPeople.every(isPersonReference);
|
|
111
|
+
}
|
|
112
|
+
function isCorrelation(value) {
|
|
113
|
+
return isRecord(value) && idCodec("thread").decode(value.threadId).ok && isBoundedString(value.turnId) && isBoundedString(value.attemptId) && (value.toolCallId === null || isBoundedString(value.toolCallId));
|
|
114
|
+
}
|
|
115
|
+
function referenceKey(value) {
|
|
116
|
+
return `${value.threadId}\x00${value.contributionId}`;
|
|
117
|
+
}
|
|
118
|
+
function isInputSource(value) {
|
|
119
|
+
if (!isRecord(value))
|
|
120
|
+
return false;
|
|
121
|
+
if (value.kind === "contribution")
|
|
122
|
+
return isContributionReference(value.reference);
|
|
123
|
+
if (value.kind === "interaction")
|
|
124
|
+
return isBoundedString(value.interactionId) && isOrigin(value.resolver);
|
|
125
|
+
return value.kind === "generated" && (value.purpose === "continuation" || value.purpose === "resolved-resource" || value.purpose === "system-context") && Array.isArray(value.basedOn) && value.basedOn.every(isContributionReference);
|
|
126
|
+
}
|
|
127
|
+
function causalReferences(groups) {
|
|
128
|
+
const references = [];
|
|
129
|
+
for (const group of groups) {
|
|
130
|
+
if (!isRecord(group) || !Array.isArray(group.sources) || !group.sources.every(isInputSource))
|
|
131
|
+
return null;
|
|
132
|
+
for (const source of group.sources) {
|
|
133
|
+
if (!isRecord(source))
|
|
134
|
+
return null;
|
|
135
|
+
if (source.kind === "contribution" && isContributionReference(source.reference))
|
|
136
|
+
references.push(source.reference);
|
|
137
|
+
if (source.kind === "generated" && Array.isArray(source.basedOn) && source.basedOn.every(isContributionReference))
|
|
138
|
+
references.push(...source.basedOn);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return references;
|
|
142
|
+
}
|
|
143
|
+
function hasCompleteCausality(groups, contributions, missing) {
|
|
144
|
+
const references = causalReferences(groups);
|
|
145
|
+
if (references === null || !contributions.every(isContribution) || !missing.every(isContributionReference))
|
|
146
|
+
return false;
|
|
147
|
+
const required = new Set(references.map(referenceKey));
|
|
148
|
+
const found = new Set;
|
|
149
|
+
for (const contribution of contributions) {
|
|
150
|
+
if (!isRecord(contribution) || !isContributionReference(contribution.reference))
|
|
151
|
+
return false;
|
|
152
|
+
const key = referenceKey(contribution.reference);
|
|
153
|
+
if (found.has(key))
|
|
154
|
+
return false;
|
|
155
|
+
found.add(key);
|
|
156
|
+
}
|
|
157
|
+
const absent = new Set;
|
|
158
|
+
for (const reference of missing) {
|
|
159
|
+
const key = referenceKey(reference);
|
|
160
|
+
if (absent.has(key) || found.has(key))
|
|
161
|
+
return false;
|
|
162
|
+
absent.add(key);
|
|
163
|
+
}
|
|
164
|
+
return required.size === found.size + absent.size && [...required].every((key) => found.has(key) || absent.has(key));
|
|
165
|
+
}
|
|
166
|
+
var provenanceCodec = {
|
|
167
|
+
decode(input) {
|
|
168
|
+
if (!isRecord(input) || input.status !== "known" && input.status !== "partial" && input.status !== "unknown") {
|
|
169
|
+
return err("invalid-input", "Invalid execution provenance.");
|
|
170
|
+
}
|
|
171
|
+
if (input.status === "unknown")
|
|
172
|
+
return (input.correlation === null || isCorrelation(input.correlation)) && isBoundedString(input.reason, 1024) ? ok(input) : err("invalid-input", "Unknown provenance needs a valid correlation and reason.");
|
|
173
|
+
if (!Array.isArray(input.inputGroups) || !Array.isArray(input.contributions))
|
|
174
|
+
return err("invalid-input", "Provenance needs input groups and contributions.");
|
|
175
|
+
if (input.status === "known") {
|
|
176
|
+
return isCorrelation(input.correlation) && hasCompleteCausality(input.inputGroups, input.contributions, []) ? ok(input) : err("invalid-input", "Known provenance needs complete correlated evidence.");
|
|
177
|
+
}
|
|
178
|
+
if ((input.correlation === null || isCorrelation(input.correlation)) && Array.isArray(input.missing) && isBoundedString(input.reason, 1024) && hasCompleteCausality(input.inputGroups, input.contributions, input.missing)) {
|
|
179
|
+
return ok(input);
|
|
180
|
+
}
|
|
181
|
+
return err("invalid-input", "Partial provenance needs complete causal accounting.");
|
|
182
|
+
},
|
|
183
|
+
encode(value) {
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
function defaultIdentityKey(instance) {
|
|
188
|
+
return `local:${instance}`;
|
|
189
|
+
}
|
|
190
|
+
function newOperationId() {
|
|
191
|
+
const random = globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
192
|
+
return `op-${random}`;
|
|
193
|
+
}
|
|
194
|
+
export {
|
|
195
|
+
provenanceCodec,
|
|
196
|
+
profileCodec,
|
|
197
|
+
newOperationId,
|
|
198
|
+
identityKeyCodec,
|
|
199
|
+
idCodec,
|
|
200
|
+
defaultIdentityKey
|
|
201
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// model-runtime.ts
|
|
3
|
+
var ID_MAX_LENGTH = 256;
|
|
4
|
+
var ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@/-]*$/;
|
|
5
|
+
function failure(code, message, retry = "never") {
|
|
6
|
+
return { code, message, retry };
|
|
7
|
+
}
|
|
8
|
+
function ok(value) {
|
|
9
|
+
return { ok: true, value };
|
|
10
|
+
}
|
|
11
|
+
function err(code, message, retry = "never") {
|
|
12
|
+
return { ok: false, error: failure(code, message, retry) };
|
|
13
|
+
}
|
|
14
|
+
function isRecord(value) {
|
|
15
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
function isBoundedString(value, maximum = ID_MAX_LENGTH) {
|
|
18
|
+
return typeof value === "string" && value.length > 0 && value.length <= maximum;
|
|
19
|
+
}
|
|
20
|
+
function idCodec(kind) {
|
|
21
|
+
return {
|
|
22
|
+
decode(input) {
|
|
23
|
+
const valid = kind === "server-session" ? isBoundedString(input, 4096) && !/[\u0000-\u0020\u007f]/.test(input) : isBoundedString(input) && ID_PATTERN.test(input);
|
|
24
|
+
if (!valid) {
|
|
25
|
+
return err("invalid-input", `Invalid ${kind} identifier.`);
|
|
26
|
+
}
|
|
27
|
+
return ok(input);
|
|
28
|
+
},
|
|
29
|
+
encode(value) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var identityKeyCodec = {
|
|
35
|
+
decode(input) {
|
|
36
|
+
if (!isBoundedString(input, 512) || /[\u0000-\u001f\u007f]/.test(input)) {
|
|
37
|
+
return err("invalid-input", "Invalid identity key.");
|
|
38
|
+
}
|
|
39
|
+
return ok(input);
|
|
40
|
+
},
|
|
41
|
+
encode(value) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
function decodePresentation(value) {
|
|
46
|
+
return isRecord(value) && isBoundedString(value.displayName, 512) && (value.handle === null || isBoundedString(value.handle, 512)) && (value.avatarUrl === null || isBoundedString(value.avatarUrl, 2048));
|
|
47
|
+
}
|
|
48
|
+
function decodeIdentity(value) {
|
|
49
|
+
if (!isRecord(value) || !identityKeyCodec.decode(value.key).ok)
|
|
50
|
+
return false;
|
|
51
|
+
if (value.kind === "person")
|
|
52
|
+
return isBoundedString(value.issuer, 512) && isBoundedString(value.subject, 512);
|
|
53
|
+
if (value.kind === "default-user")
|
|
54
|
+
return isBoundedString(value.instanceId);
|
|
55
|
+
if (value.kind === "machine") {
|
|
56
|
+
return isBoundedString(value.instanceId) && (value.hostId === null || isBoundedString(value.hostId, 512));
|
|
57
|
+
}
|
|
58
|
+
return value.kind === "external" && isBoundedString(value.pluginId) && isBoundedString(value.subject, 512);
|
|
59
|
+
}
|
|
60
|
+
var profileCodec = {
|
|
61
|
+
decode(input) {
|
|
62
|
+
if (!isRecord(input) || !decodeIdentity(input.identity) || !decodePresentation(input.presentation) || !isBoundedString(input.revision) || input.status !== "current" && input.status !== "historical") {
|
|
63
|
+
return err("invalid-input", "Invalid identity profile.");
|
|
64
|
+
}
|
|
65
|
+
return ok(input);
|
|
66
|
+
},
|
|
67
|
+
encode(value) {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
function isContributionReference(value) {
|
|
72
|
+
return isRecord(value) && idCodec("thread").decode(value.threadId).ok && idCodec("contribution").decode(value.contributionId).ok;
|
|
73
|
+
}
|
|
74
|
+
function isPersonReference(value) {
|
|
75
|
+
return isRecord(value) && (value.kind === "person" || value.kind === "default-user") && decodeIdentity(value);
|
|
76
|
+
}
|
|
77
|
+
function isMachineReference(value) {
|
|
78
|
+
return isRecord(value) && value.kind === "machine" && decodeIdentity(value);
|
|
79
|
+
}
|
|
80
|
+
function isActorSnapshot(value) {
|
|
81
|
+
if (!isRecord(value) || !decodeIdentity(value.identity) || !decodePresentation(value.presentation))
|
|
82
|
+
return false;
|
|
83
|
+
const evidence = value.evidence;
|
|
84
|
+
if (evidence !== "provider-verified" && evidence !== "local-user" && evidence !== "upstream-default" && evidence !== "integration-asserted" && evidence !== "legacy" && evidence !== "machine")
|
|
85
|
+
return false;
|
|
86
|
+
return isMachineReference(value.identity) ? evidence === "machine" : evidence !== "machine";
|
|
87
|
+
}
|
|
88
|
+
function isOrigin(value) {
|
|
89
|
+
if (!isRecord(value))
|
|
90
|
+
return false;
|
|
91
|
+
if (value.kind === "person") {
|
|
92
|
+
const actor = value.actor;
|
|
93
|
+
return isActorSnapshot(actor) && isRecord(actor) && isPersonReference(actor.identity);
|
|
94
|
+
}
|
|
95
|
+
if (value.kind === "machine") {
|
|
96
|
+
const actor = value.actor;
|
|
97
|
+
return isActorSnapshot(actor) && isRecord(actor) && isMachineReference(actor.identity) && isRecord(actor) && actor.evidence === "machine";
|
|
98
|
+
}
|
|
99
|
+
if (value.kind === "external") {
|
|
100
|
+
const actor = value.actor;
|
|
101
|
+
return isActorSnapshot(actor) && isRecord(actor) && isRecord(actor.identity) && actor.identity.kind === "external" && actor.evidence !== "machine";
|
|
102
|
+
}
|
|
103
|
+
if (value.kind === "agent")
|
|
104
|
+
return value.agentId === null || isBoundedString(value.agentId);
|
|
105
|
+
if (value.kind === "system")
|
|
106
|
+
return isBoundedString(value.reason, 1024);
|
|
107
|
+
return value.kind === "unknown" && (value.reason === "legacy" || value.reason === "upstream-unattributed" || value.reason === "missing-source");
|
|
108
|
+
}
|
|
109
|
+
function isContribution(value) {
|
|
110
|
+
return isRecord(value) && isContributionReference(value.reference) && isOrigin(value.author) && (value.latestEditor === null || isActorSnapshot(value.latestEditor)) && isBoundedString(value.acceptedAt, 256) && Array.isArray(value.mentionedPeople) && value.mentionedPeople.every(isPersonReference);
|
|
111
|
+
}
|
|
112
|
+
function isCorrelation(value) {
|
|
113
|
+
return isRecord(value) && idCodec("thread").decode(value.threadId).ok && isBoundedString(value.turnId) && isBoundedString(value.attemptId) && (value.toolCallId === null || isBoundedString(value.toolCallId));
|
|
114
|
+
}
|
|
115
|
+
function referenceKey(value) {
|
|
116
|
+
return `${value.threadId}\x00${value.contributionId}`;
|
|
117
|
+
}
|
|
118
|
+
function isInputSource(value) {
|
|
119
|
+
if (!isRecord(value))
|
|
120
|
+
return false;
|
|
121
|
+
if (value.kind === "contribution")
|
|
122
|
+
return isContributionReference(value.reference);
|
|
123
|
+
if (value.kind === "interaction")
|
|
124
|
+
return isBoundedString(value.interactionId) && isOrigin(value.resolver);
|
|
125
|
+
return value.kind === "generated" && (value.purpose === "continuation" || value.purpose === "resolved-resource" || value.purpose === "system-context") && Array.isArray(value.basedOn) && value.basedOn.every(isContributionReference);
|
|
126
|
+
}
|
|
127
|
+
function causalReferences(groups) {
|
|
128
|
+
const references = [];
|
|
129
|
+
for (const group of groups) {
|
|
130
|
+
if (!isRecord(group) || !Array.isArray(group.sources) || !group.sources.every(isInputSource))
|
|
131
|
+
return null;
|
|
132
|
+
for (const source of group.sources) {
|
|
133
|
+
if (!isRecord(source))
|
|
134
|
+
return null;
|
|
135
|
+
if (source.kind === "contribution" && isContributionReference(source.reference))
|
|
136
|
+
references.push(source.reference);
|
|
137
|
+
if (source.kind === "generated" && Array.isArray(source.basedOn) && source.basedOn.every(isContributionReference))
|
|
138
|
+
references.push(...source.basedOn);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return references;
|
|
142
|
+
}
|
|
143
|
+
function hasCompleteCausality(groups, contributions, missing) {
|
|
144
|
+
const references = causalReferences(groups);
|
|
145
|
+
if (references === null || !contributions.every(isContribution) || !missing.every(isContributionReference))
|
|
146
|
+
return false;
|
|
147
|
+
const required = new Set(references.map(referenceKey));
|
|
148
|
+
const found = new Set;
|
|
149
|
+
for (const contribution of contributions) {
|
|
150
|
+
if (!isRecord(contribution) || !isContributionReference(contribution.reference))
|
|
151
|
+
return false;
|
|
152
|
+
const key = referenceKey(contribution.reference);
|
|
153
|
+
if (found.has(key))
|
|
154
|
+
return false;
|
|
155
|
+
found.add(key);
|
|
156
|
+
}
|
|
157
|
+
const absent = new Set;
|
|
158
|
+
for (const reference of missing) {
|
|
159
|
+
const key = referenceKey(reference);
|
|
160
|
+
if (absent.has(key) || found.has(key))
|
|
161
|
+
return false;
|
|
162
|
+
absent.add(key);
|
|
163
|
+
}
|
|
164
|
+
return required.size === found.size + absent.size && [...required].every((key) => found.has(key) || absent.has(key));
|
|
165
|
+
}
|
|
166
|
+
var provenanceCodec = {
|
|
167
|
+
decode(input) {
|
|
168
|
+
if (!isRecord(input) || input.status !== "known" && input.status !== "partial" && input.status !== "unknown") {
|
|
169
|
+
return err("invalid-input", "Invalid execution provenance.");
|
|
170
|
+
}
|
|
171
|
+
if (input.status === "unknown")
|
|
172
|
+
return (input.correlation === null || isCorrelation(input.correlation)) && isBoundedString(input.reason, 1024) ? ok(input) : err("invalid-input", "Unknown provenance needs a valid correlation and reason.");
|
|
173
|
+
if (!Array.isArray(input.inputGroups) || !Array.isArray(input.contributions))
|
|
174
|
+
return err("invalid-input", "Provenance needs input groups and contributions.");
|
|
175
|
+
if (input.status === "known") {
|
|
176
|
+
return isCorrelation(input.correlation) && hasCompleteCausality(input.inputGroups, input.contributions, []) ? ok(input) : err("invalid-input", "Known provenance needs complete correlated evidence.");
|
|
177
|
+
}
|
|
178
|
+
if ((input.correlation === null || isCorrelation(input.correlation)) && Array.isArray(input.missing) && isBoundedString(input.reason, 1024) && hasCompleteCausality(input.inputGroups, input.contributions, input.missing)) {
|
|
179
|
+
return ok(input);
|
|
180
|
+
}
|
|
181
|
+
return err("invalid-input", "Partial provenance needs complete causal accounting.");
|
|
182
|
+
},
|
|
183
|
+
encode(value) {
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
function defaultIdentityKey(instance) {
|
|
188
|
+
return `local:${instance}`;
|
|
189
|
+
}
|
|
190
|
+
function newOperationId() {
|
|
191
|
+
const random = globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
192
|
+
return `op-${random}`;
|
|
193
|
+
}
|
|
194
|
+
function newConflictToken() {
|
|
195
|
+
return `conflict-${globalThis.crypto?.randomUUID?.() ?? Date.now().toString(36)}`;
|
|
196
|
+
}
|
|
197
|
+
export {
|
|
198
|
+
provenanceCodec,
|
|
199
|
+
profileCodec,
|
|
200
|
+
ok,
|
|
201
|
+
newOperationId,
|
|
202
|
+
newConflictToken,
|
|
203
|
+
identityKeyCodec,
|
|
204
|
+
idCodec,
|
|
205
|
+
err,
|
|
206
|
+
defaultIdentityKey
|
|
207
|
+
};
|