@agentunion/fastaun 0.5.21 → 0.5.23
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/CHANGELOG.md +58 -1
- package/_packed_docs/CHANGELOG.md +58 -1
- package/_packed_docs/INDEX.md +469 -453
- package/_packed_docs/KITE_DOCS_GUIDE.md +169 -164
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +307 -67
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +5 -5
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +669 -666
- package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
- package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +16 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +10 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +3 -1
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +2 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +138 -134
- package/_packed_docs/sdk/INDEX.md +255 -239
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +939 -930
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +312 -363
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +322 -553
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +4 -4
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +484 -480
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +190 -97
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +158 -127
- package/dist/agent-md.d.ts +16 -2
- package/dist/agent-md.js +59 -23
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +1 -0
- package/dist/aid-store.js +43 -8
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts +7 -0
- package/dist/auth.js +222 -70
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +28 -0
- package/dist/client/delivery.js +399 -44
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +3 -0
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/rpc-pipeline.js +28 -2
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +109 -39
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +114 -26
- package/dist/client.js.map +1 -1
- package/dist/group-fs.d.ts +1 -0
- package/dist/group-fs.js +37 -19
- package/dist/group-fs.js.map +1 -1
- package/dist/org-protocol.d.ts +11 -0
- package/dist/org-protocol.js +154 -19
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +21 -3
- package/dist/ownership-v21.js +135 -37
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +7 -2
- package/dist/ownership-workflow.js +173 -17
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/storage/lowlevel.d.ts +6 -0
- package/dist/storage/lowlevel.js +24 -7
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/read-cache.d.ts +70 -0
- package/dist/storage/read-cache.js +625 -0
- package/dist/storage/read-cache.js.map +1 -0
- package/dist/storage/vfs.d.ts +2 -0
- package/dist/storage/vfs.js +50 -15
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +21 -1
- package/dist/tools/cross-sdk-agent.js +301 -19
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.js +6 -2
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/ownership-v21.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export interface OwnershipConsensusResult {
|
|
|
59
59
|
owner_aid: string | null;
|
|
60
60
|
relation_version: number;
|
|
61
61
|
lock: 'locked' | 'unlocked';
|
|
62
|
+
ownership_status?: string;
|
|
62
63
|
agent_md_etag: string;
|
|
63
64
|
agent_md_sha256: string;
|
|
64
65
|
owner_md_sha256: string;
|
|
@@ -84,6 +85,9 @@ export interface OwnershipAgentObservation {
|
|
|
84
85
|
protocol: string;
|
|
85
86
|
relation_version: number;
|
|
86
87
|
lock: 'locked' | 'unlocked';
|
|
88
|
+
ownership_status?: string;
|
|
89
|
+
pending?: boolean;
|
|
90
|
+
stage_supported?: boolean;
|
|
87
91
|
owner_aid?: string | null;
|
|
88
92
|
observed_at: number;
|
|
89
93
|
recovery_ready?: boolean;
|
|
@@ -123,6 +127,7 @@ export interface OwnershipSavedFile {
|
|
|
123
127
|
}
|
|
124
128
|
export interface OwnershipFileTask {
|
|
125
129
|
operation_id?: string;
|
|
130
|
+
stage?: boolean;
|
|
126
131
|
operation: 'bind' | 'release' | 'transfer';
|
|
127
132
|
sub_aid: string;
|
|
128
133
|
owner_aid: string;
|
|
@@ -137,6 +142,16 @@ export interface OwnershipFileTask {
|
|
|
137
142
|
sha256: string;
|
|
138
143
|
etag: string;
|
|
139
144
|
statement: OwnershipStatementV21 | null;
|
|
145
|
+
pending?: boolean;
|
|
146
|
+
};
|
|
147
|
+
pending_agent_md?: {
|
|
148
|
+
raw: string;
|
|
149
|
+
sha256: string;
|
|
150
|
+
etag: string;
|
|
151
|
+
};
|
|
152
|
+
owner_proposal?: {
|
|
153
|
+
raw: string;
|
|
154
|
+
sha256: string;
|
|
140
155
|
};
|
|
141
156
|
base_owner_md?: {
|
|
142
157
|
exists: boolean;
|
|
@@ -153,10 +168,10 @@ export interface OwnershipFileDependencies {
|
|
|
153
168
|
currentType?(): string;
|
|
154
169
|
now(): number;
|
|
155
170
|
readAgentMdFresh(subAid: string): Promise<OwnershipAgentObservation>;
|
|
156
|
-
submitAgentMdRaw(subAid: string, raw: string, condition: OwnershipSavedFile['condition'], assertActive?: () => void): Promise<OwnershipAgentObservation>;
|
|
171
|
+
submitAgentMdRaw(subAid: string, raw: string, condition: OwnershipSavedFile['condition'], assertActive?: () => void, stage?: boolean): Promise<OwnershipAgentObservation>;
|
|
157
172
|
readOwnerMd(ownerAid: string, subAid: string): Promise<OwnershipOwnerObservation>;
|
|
158
173
|
writeOwnerMd(ownerAid: string, subAid: string, raw: string, original?: Pick<OwnershipOwnerObservation, 'exists' | 'content' | 'sha256' | 'version'>, assertActive?: () => void): Promise<OwnershipOwnerObservation>;
|
|
159
|
-
deleteOwnerMd(ownerAid: string, subAid: string): Promise<unknown>;
|
|
174
|
+
deleteOwnerMd(ownerAid: string, subAid: string, expectedVersion: number): Promise<unknown>;
|
|
160
175
|
resolveCertificate(aid: string, fingerprint: string, purpose?: 'signing' | 'group_identity'): Promise<OwnershipCertificate>;
|
|
161
176
|
}
|
|
162
177
|
export declare function ownershipFailure(code: string, reason: string, retryable?: boolean): StateError;
|
|
@@ -172,8 +187,10 @@ export declare class OwnershipFiles {
|
|
|
172
187
|
declareOwneraid(task: OwnershipFileTask): Promise<OwnershipAgentObservation>;
|
|
173
188
|
revokeSubaid(task: OwnershipFileTask): Promise<OwnershipOwnerObservation>;
|
|
174
189
|
revokeOwneraid(task: OwnershipFileTask): Promise<OwnershipAgentObservation>;
|
|
190
|
+
cancelPendingBind(task: OwnershipFileTask, candidate: OwnershipSavedFile): Promise<OwnershipAgentObservation>;
|
|
175
191
|
transferOwneraid(task: OwnershipFileTask): Promise<OwnershipOwnerObservation>;
|
|
176
192
|
cleanupOwnerFile(task: OwnershipFileTask): Promise<void>;
|
|
193
|
+
cancelOwnerProposal(task: OwnershipFileTask): Promise<void>;
|
|
177
194
|
readAgent(subAid: string): Promise<OwnershipAgentObservation>;
|
|
178
195
|
readOwner(ownerAid: string, subAid: string): Promise<OwnershipOwnerObservation>;
|
|
179
196
|
verifyFile(raw: string, role: OwnershipFileRole, subAid: string, ownerAid?: string): Promise<OwnershipFile>;
|
|
@@ -183,6 +200,7 @@ export declare class OwnershipFiles {
|
|
|
183
200
|
private statement;
|
|
184
201
|
private assertBase;
|
|
185
202
|
private requireOriginal;
|
|
203
|
+
private currentConsensus;
|
|
186
204
|
private savedFile;
|
|
187
205
|
private validSavedCondition;
|
|
188
206
|
private publishOwner;
|
|
@@ -203,7 +221,7 @@ export declare class OwnershipStorageAdapter {
|
|
|
203
221
|
readObject(ownerAid: string, path: string): Promise<OwnershipOwnerObservation>;
|
|
204
222
|
readOwnerMd(ownerAid: string, subAid: string): Promise<OwnershipOwnerObservation>;
|
|
205
223
|
writeOwnerMd(ownerAid: string, subAid: string, raw: string, original?: Pick<OwnershipOwnerObservation, 'exists' | 'content' | 'sha256' | 'version'>, assertActive?: () => void): Promise<OwnershipOwnerObservation>;
|
|
206
|
-
deleteOwnerMd(ownerAid: string, subAid: string): Promise<void>;
|
|
224
|
+
deleteOwnerMd(ownerAid: string, subAid: string, expectedVersion: number): Promise<void>;
|
|
207
225
|
private requireLocal;
|
|
208
226
|
}
|
|
209
227
|
export {};
|
package/dist/ownership-v21.js
CHANGED
|
@@ -239,18 +239,36 @@ export class OwnershipFiles {
|
|
|
239
239
|
const began = this.deps.now();
|
|
240
240
|
const result = { status: 'unavailable', sub_aid: subAid, owner_aid: null, relation_version: 0, lock: 'unlocked', agent_md_etag: '', agent_md_sha256: '', owner_md_sha256: '' };
|
|
241
241
|
try {
|
|
242
|
-
|
|
242
|
+
let before = await this.readAgent(subAid);
|
|
243
|
+
if (before.ownership_status)
|
|
244
|
+
result.ownership_status = before.ownership_status;
|
|
243
245
|
Object.assign(result, { relation_version: before.relation_version, lock: before.lock, agent_md_etag: before.etag, agent_md_sha256: before.exists ? ownershipSha256(before.content) : '' });
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
246
|
+
let agent = before.exists ? await this.verifyFile(before.content, 'agent', subAid) : undefined;
|
|
247
|
+
let statement = agent?.statement;
|
|
248
|
+
let projectionRetried = false;
|
|
249
|
+
const refreshProjection = async () => {
|
|
250
|
+
if (projectionRetried)
|
|
251
|
+
throw ownershipFailure('unavailable', 'NS relationship projection does not match current signed materials', true);
|
|
252
|
+
projectionRetried = true;
|
|
253
|
+
const current = await this.readAgent(subAid);
|
|
254
|
+
if (current.exists !== before.exists || current.content !== before.content)
|
|
255
|
+
throw ownershipFailure('unavailable', 'agent.md changed while rechecking NS projection', true);
|
|
256
|
+
const currentAgent = current.exists ? await this.verifyFile(current.content, 'agent', subAid) : undefined;
|
|
257
|
+
const currentStatement = currentAgent?.statement;
|
|
258
|
+
const currentOwner = current.lock === 'locked' ? currentStatement?.owner_aid : null;
|
|
259
|
+
if (current.relation_version !== (currentStatement?.relation_version ?? 0) || current.lock === 'locked' && !currentStatement || current.owner_aid !== undefined && current.owner_aid !== currentOwner)
|
|
260
|
+
throw ownershipFailure('unavailable', 'NS relationship projection still does not match agent.md', true);
|
|
261
|
+
before = current;
|
|
262
|
+
agent = currentAgent;
|
|
263
|
+
statement = currentStatement;
|
|
264
|
+
Object.assign(result, { relation_version: before.relation_version, lock: before.lock, agent_md_etag: before.etag, agent_md_sha256: before.exists ? ownershipSha256(before.content) : '' });
|
|
265
|
+
};
|
|
266
|
+
const agentProjectionMatches = () => before.relation_version === (statement?.relation_version ?? 0) && !(before.lock === 'locked' && !statement) && (before.owner_aid === undefined || before.owner_aid === (before.lock === 'locked' ? statement?.owner_aid ?? null : null));
|
|
267
|
+
if (!agentProjectionMatches())
|
|
268
|
+
await refreshProjection();
|
|
269
|
+
if (!agentProjectionMatches())
|
|
270
|
+
throw ownershipFailure('unavailable', 'NS relationship projection does not match agent.md', true);
|
|
271
|
+
result.owner_aid = before.lock === 'locked' ? statement.owner_aid : null;
|
|
254
272
|
result.status = statement ? 'single_sided' : 'unbound';
|
|
255
273
|
const ownerAid = statement?.owner_aid ?? target?.owner_aid;
|
|
256
274
|
let ownerBefore;
|
|
@@ -261,7 +279,10 @@ export class OwnershipFiles {
|
|
|
261
279
|
result.owner_md = { owner_aid: ownerAid, bucket: 'default', path: `sub_aids/${subAid}/owner.md`, exists: owner.exists, content: owner.content, sha256: owner.sha256 ?? '', observed_at: owner.observed_at };
|
|
262
280
|
if (owner.exists) {
|
|
263
281
|
const declaration = await this.verifyFile(owner.content, 'owner', subAid, ownerAid);
|
|
264
|
-
if (statement) {
|
|
282
|
+
if (statement && (before.pending || before.ownership_status === 'pending')) {
|
|
283
|
+
result.status = 'single_sided';
|
|
284
|
+
}
|
|
285
|
+
else if (statement) {
|
|
265
286
|
if (declaration.statement.relation_version !== before.relation_version)
|
|
266
287
|
throw new ValidationError('ownership relation_version mismatch');
|
|
267
288
|
result.status = declaration.action === 'release' ? 'released' : 'consensus';
|
|
@@ -271,10 +292,14 @@ export class OwnershipFiles {
|
|
|
271
292
|
}
|
|
272
293
|
}
|
|
273
294
|
else if (statement)
|
|
274
|
-
result.status = 'released';
|
|
295
|
+
result.status = before.pending || before.ownership_status === 'pending' ? 'single_sided' : 'released';
|
|
275
296
|
}
|
|
276
|
-
if (
|
|
277
|
-
|
|
297
|
+
if (before.lock !== (result.status === 'consensus' ? 'locked' : 'unlocked')) {
|
|
298
|
+
await refreshProjection();
|
|
299
|
+
if (before.lock !== (result.status === 'consensus' ? 'locked' : 'unlocked'))
|
|
300
|
+
throw ownershipFailure('unavailable', 'NS lock projection still conflicts with signed ownership files', true);
|
|
301
|
+
}
|
|
302
|
+
result.lock = before.lock;
|
|
278
303
|
result.owner_aid = result.status === 'consensus' ? statement.owner_aid : null;
|
|
279
304
|
const after = await this.readAgent(subAid);
|
|
280
305
|
if (ownerAid && ownerBefore) {
|
|
@@ -313,13 +338,22 @@ export class OwnershipFiles {
|
|
|
313
338
|
await this.assertBase(task, agent);
|
|
314
339
|
if (task.operation === 'transfer')
|
|
315
340
|
await this.requireTransfer(task);
|
|
341
|
+
if (task.operation === 'bind' && task.stage)
|
|
342
|
+
return { owner: ownerAid, ownership: { statement: this.statement(task, ownerAid, task.target_relation_version) } };
|
|
316
343
|
const owner = await this.readOwner(ownerAid, task.sub_aid);
|
|
317
344
|
if (!owner.exists)
|
|
318
345
|
throw ownershipFailure('unavailable', 'target owner declaration is missing', true);
|
|
319
346
|
const declaration = await this.verifyFile(owner.content, 'owner', task.sub_aid, ownerAid);
|
|
347
|
+
if (task.owner_proposal && (owner.content !== task.owner_proposal.raw || owner.sha256 !== task.owner_proposal.sha256))
|
|
348
|
+
throw ownershipFailure('conflict', 'owner binding proposal changed');
|
|
349
|
+
const savedOwner = task.files.owner;
|
|
350
|
+
if (savedOwner && (savedOwner.raw !== owner.content || savedOwner.hash !== owner.sha256))
|
|
351
|
+
throw ownershipFailure('conflict', 'fixed target owner declaration changed');
|
|
352
|
+
if (declaration.action === 'declare' && declaration.statement.relation_version < task.target_relation_version)
|
|
353
|
+
throw ownershipFailure('unavailable', 'target owner declaration is not ready', true);
|
|
320
354
|
if (declaration.action !== 'declare' || declaration.statement.relation_version !== task.target_relation_version)
|
|
321
355
|
throw ownershipFailure('conflict', 'target owner declaration does not match this task');
|
|
322
|
-
return { owner: ownerAid, ownership: { statement: this.statement(task, ownerAid, task.target_relation_version) } };
|
|
356
|
+
return { owner: ownerAid, ownership: { statement: task.owner_proposal ? declaration.statement : this.statement(task, ownerAid, task.target_relation_version) } };
|
|
323
357
|
});
|
|
324
358
|
}
|
|
325
359
|
async revokeSubaid(task) {
|
|
@@ -333,8 +367,9 @@ export class OwnershipFiles {
|
|
|
333
367
|
async revokeOwneraid(task) {
|
|
334
368
|
this.requireLocal(task.sub_aid);
|
|
335
369
|
return this.publishAgent(task, async (agent) => {
|
|
336
|
-
|
|
337
|
-
|
|
370
|
+
const consensus = await this.currentConsensus(agent);
|
|
371
|
+
if (consensus.lock === 'locked')
|
|
372
|
+
throw ownershipFailure('owner_locked', 'current ownership materials have not confirmed release');
|
|
338
373
|
const parsed = parseOwnershipFile(agent.content, 'agent', { expectedSubAid: task.sub_aid });
|
|
339
374
|
if (!parsed.statement && agent.relation_version === 0)
|
|
340
375
|
return {};
|
|
@@ -347,6 +382,19 @@ export class OwnershipFiles {
|
|
|
347
382
|
return {};
|
|
348
383
|
}, true);
|
|
349
384
|
}
|
|
385
|
+
async cancelPendingBind(task, candidate) {
|
|
386
|
+
this.requireLocal(task.sub_aid);
|
|
387
|
+
const current = await this.readAgent(task.sub_aid), saved = task.files.agent;
|
|
388
|
+
if (!(saved && current.content === saved.raw && ownershipSha256(current.content) === saved.hash)) {
|
|
389
|
+
if (current.lock !== 'unlocked' || !(current.pending || current.ownership_status === 'pending') || current.content !== candidate.raw || ownershipSha256(current.content) !== candidate.hash || candidate.published_etag !== undefined && current.etag !== candidate.published_etag)
|
|
390
|
+
throw ownershipFailure('conflict', 'pending ownership candidate changed before rejection cleanup');
|
|
391
|
+
}
|
|
392
|
+
return this.publishAgent({ ...task, operation: 'release', base_relation_version: task.target_relation_version }, async (agent) => {
|
|
393
|
+
if (agent.lock !== 'unlocked' || !(agent.pending || agent.ownership_status === 'pending') || agent.content !== candidate.raw || ownershipSha256(agent.content) !== candidate.hash || candidate.published_etag !== undefined && agent.etag !== candidate.published_etag)
|
|
394
|
+
throw ownershipFailure('conflict', 'pending ownership candidate changed before signing rejection cleanup');
|
|
395
|
+
return {};
|
|
396
|
+
}, true);
|
|
397
|
+
}
|
|
350
398
|
async transferOwneraid(task) {
|
|
351
399
|
this.requireLocal(task.owner_aid);
|
|
352
400
|
ownershipAid(task.new_owner_aid, 'new_owner_aid');
|
|
@@ -387,12 +435,30 @@ export class OwnershipFiles {
|
|
|
387
435
|
if (beforeDelete.exists && (beforeDelete.content !== source.raw || beforeDelete.sha256 !== source.hash))
|
|
388
436
|
throw ownershipFailure('conflict', 'owner file changed before cleanup');
|
|
389
437
|
if (beforeDelete.exists) {
|
|
438
|
+
if (!Number.isSafeInteger(beforeDelete.version) || beforeDelete.version <= 0)
|
|
439
|
+
throw ownershipFailure('unavailable', 'Storage owner.md version is unavailable', true);
|
|
390
440
|
task.assertActive?.();
|
|
391
|
-
await this.deps.deleteOwnerMd(task.owner_aid, task.sub_aid);
|
|
441
|
+
await this.deps.deleteOwnerMd(task.owner_aid, task.sub_aid, beforeDelete.version);
|
|
392
442
|
}
|
|
393
443
|
task.files.cleanup.deleted = true;
|
|
394
444
|
await task.persist();
|
|
395
445
|
}
|
|
446
|
+
async cancelOwnerProposal(task) {
|
|
447
|
+
this.requireLocal(task.owner_aid);
|
|
448
|
+
const source = this.savedFile(task, 'owner');
|
|
449
|
+
if (!source)
|
|
450
|
+
throw ownershipFailure('conflict', 'owner binding proposal is unavailable');
|
|
451
|
+
await this.assertBase(task, await this.readAgent(task.sub_aid));
|
|
452
|
+
const current = await this.readOwner(task.owner_aid, task.sub_aid);
|
|
453
|
+
if (!current.exists)
|
|
454
|
+
return;
|
|
455
|
+
if (current.content !== source.raw || current.sha256 !== source.hash)
|
|
456
|
+
throw ownershipFailure('conflict', 'owner binding proposal changed before rejection cleanup');
|
|
457
|
+
if (!Number.isSafeInteger(current.version) || current.version <= 0)
|
|
458
|
+
throw ownershipFailure('unavailable', 'Storage owner.md version is unavailable', true);
|
|
459
|
+
task.assertActive?.();
|
|
460
|
+
await this.deps.deleteOwnerMd(task.owner_aid, task.sub_aid, current.version);
|
|
461
|
+
}
|
|
396
462
|
async readAgent(subAid) {
|
|
397
463
|
if (this.deps.currentType && subAid === this.deps.currentAid().aid)
|
|
398
464
|
requireOwnershipApplicable(this.deps.currentType());
|
|
@@ -465,6 +531,15 @@ export class OwnershipFiles {
|
|
|
465
531
|
}
|
|
466
532
|
async assertBase(task, agent) {
|
|
467
533
|
ownershipInteger(task.base_relation_version, 'base_relation_version', 0);
|
|
534
|
+
const candidate = task.files.agent ? { raw: task.files.agent.raw, sha256: task.files.agent.hash, etag: task.files.agent.published_etag } : task.pending_agent_md ?? (task.base_agent_md?.pending ? task.base_agent_md : undefined);
|
|
535
|
+
if (task.operation === 'bind' && task.base_agent_md?.pending && agent.lock === 'unlocked' && (agent.pending || agent.ownership_status === 'pending') && agent.relation_version === task.base_relation_version && agent.content === task.base_agent_md.raw && ownershipSha256(agent.content) === task.base_agent_md.sha256 && agent.etag === task.base_agent_md.etag)
|
|
536
|
+
return;
|
|
537
|
+
if (task.operation === 'bind' && (agent.pending || agent.ownership_status === 'pending') && agent.lock === 'unlocked' && agent.relation_version === task.target_relation_version && candidate && agent.content === candidate.raw && ownershipSha256(agent.content) === candidate.sha256 && (!candidate.etag || agent.etag === candidate.etag)) {
|
|
538
|
+
const parsed = await this.verifyFile(agent.content, 'agent', task.sub_aid);
|
|
539
|
+
if (parsed.statement?.owner_aid !== task.owner_aid)
|
|
540
|
+
throw ownershipFailure('conflict', 'pending owner does not match this task');
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
468
543
|
const target = ownershipInteger(task.target_relation_version, 'target_relation_version');
|
|
469
544
|
if (target !== task.base_relation_version + 1 && !(task.operation === 'release' && target === task.base_relation_version) || agent.relation_version !== task.base_relation_version)
|
|
470
545
|
throw ownershipFailure('conflict', 'NS relation_version changed');
|
|
@@ -475,17 +550,19 @@ export class OwnershipFiles {
|
|
|
475
550
|
}
|
|
476
551
|
const parsed = await this.verifyFile(agent.content, 'agent', task.sub_aid);
|
|
477
552
|
const base = task.base_agent_md;
|
|
553
|
+
if (base?.pending && (agent.content !== base.raw || agent.etag !== base.etag))
|
|
554
|
+
throw ownershipFailure('conflict', 'the pending ownership original was replaced');
|
|
478
555
|
if (base && (agent.exists !== base.exists || (base.statement ? !parsed.statement || Object.keys(base.statement).some((field) => base.statement[field] !== parsed.statement[field]) : parsed.statement || agent.content !== base.raw || ownershipSha256(agent.content) !== base.sha256)))
|
|
479
556
|
throw ownershipFailure('conflict', 'the original ownership statement was replaced');
|
|
480
557
|
if (agent.relation_version !== (parsed.statement?.relation_version ?? 0))
|
|
481
558
|
throw ownershipFailure('unavailable', 'NS relation metadata does not match agent.md', true);
|
|
482
559
|
if (task.operation === 'bind' && parsed.frontmatter.type === 'human')
|
|
483
560
|
throw ownershipFailure('invalid', 'human cannot declare an owner');
|
|
484
|
-
if (task.operation === 'bind' && agent.lock
|
|
561
|
+
if (task.operation === 'bind' && parsed.statement && !(agent.lock === 'unlocked' && (agent.pending || agent.ownership_status === 'pending')) && (await this.currentConsensus(agent)).status !== 'released')
|
|
485
562
|
throw ownershipFailure('owner_locked', 'an existing owner relation is locked');
|
|
486
|
-
if (task.operation === 'bind' && parsed.statement?.owner_aid === this.targetOwner(task))
|
|
563
|
+
if (task.operation === 'bind' && parsed.statement?.owner_aid === this.targetOwner(task) && !(agent.pending || agent.ownership_status === 'pending'))
|
|
487
564
|
throw ownershipFailure('conflict', 'clear the released agent.md statement before binding the same owner');
|
|
488
|
-
if (task.operation !== 'bind' && (
|
|
565
|
+
if (task.operation !== 'bind' && (parsed.statement?.owner_aid !== task.owner_aid || parsed.statement.relation_version !== task.base_relation_version || (await this.currentConsensus(agent)).status !== 'consensus'))
|
|
489
566
|
throw ownershipFailure('conflict', 'the original relation is no longer current');
|
|
490
567
|
}
|
|
491
568
|
async requireOriginal(task) {
|
|
@@ -494,6 +571,14 @@ export class OwnershipFiles {
|
|
|
494
571
|
if (consensus.status !== 'consensus' || consensus.owner_aid !== task.owner_aid || consensus.relation_version !== task.base_relation_version)
|
|
495
572
|
throw ownershipFailure(consensus.status === 'invalid' ? 'invalid' : 'unavailable', 'the original ownership consensus cannot be confirmed', consensus.status !== 'invalid');
|
|
496
573
|
}
|
|
574
|
+
async currentConsensus(agent) {
|
|
575
|
+
const result = await this.checkConsensus(agent.sub_aid);
|
|
576
|
+
if (result.status === 'invalid' || result.status === 'unavailable' || result.status === 'not_applicable')
|
|
577
|
+
throw ownershipFailure(result.code ?? result.status, result.reason ?? 'ownership materials cannot be verified', result.retryable);
|
|
578
|
+
if (result.relation_version !== agent.relation_version || result.agent_md_etag !== agent.etag || result.agent_md_sha256 !== (agent.exists ? ownershipSha256(agent.content) : ''))
|
|
579
|
+
throw ownershipFailure('unavailable', 'agent.md changed during ownership verification', true);
|
|
580
|
+
return result;
|
|
581
|
+
}
|
|
497
582
|
savedFile(task, key) {
|
|
498
583
|
const saved = task.files[key];
|
|
499
584
|
if (saved && (typeof saved.raw !== 'string' || saved.hash !== ownershipSha256(saved.raw) || !this.validSavedCondition(key, saved.condition) || saved.published_etag !== undefined && (typeof saved.published_etag !== 'string' || !saved.published_etag)))
|
|
@@ -562,6 +647,8 @@ export class OwnershipFiles {
|
|
|
562
647
|
async publishAgent(task, prepare, cleanup = false) {
|
|
563
648
|
let saved = this.savedFile(task, 'agent');
|
|
564
649
|
const current = await this.readAgent(task.sub_aid);
|
|
650
|
+
if (task.stage && !cleanup && current.stage_supported !== true)
|
|
651
|
+
throw ownershipFailure('unsupported_protocol', 'NS does not support Ownership Stage', true);
|
|
565
652
|
if (!saved) {
|
|
566
653
|
const fields = await prepare(current);
|
|
567
654
|
if (cleanup && !parseOwnershipFile(current.content, 'agent', { now: this.deps.now() }).statement)
|
|
@@ -573,7 +660,8 @@ export class OwnershipFiles {
|
|
|
573
660
|
await task.persist();
|
|
574
661
|
}
|
|
575
662
|
await this.verifyFile(saved.raw, 'agent', task.sub_aid);
|
|
576
|
-
|
|
663
|
+
const pendingBind = task.operation === 'bind' && !cleanup && current.lock === 'unlocked' && (current.pending || current.ownership_status === 'pending');
|
|
664
|
+
if (current.exists && ownershipSha256(current.content) === saved.hash && current.content === saved.raw && current.relation_version === (cleanup ? 0 : task.target_relation_version) && (current.lock === (cleanup ? 'unlocked' : 'locked') || pendingBind)) {
|
|
577
665
|
if (saved.published_etag !== undefined && current.etag !== saved.published_etag)
|
|
578
666
|
throw ownershipFailure('conflict', 'agent.md published ETag changed');
|
|
579
667
|
saved.published_etag = current.etag;
|
|
@@ -583,26 +671,34 @@ export class OwnershipFiles {
|
|
|
583
671
|
if (saved.condition.if_none_match === '*' ? current.exists : !current.exists || current.etag !== saved.condition.if_match)
|
|
584
672
|
throw ownershipFailure('conflict', 'agent.md original ETag condition changed');
|
|
585
673
|
if (cleanup) {
|
|
586
|
-
if (current.lock !== 'unlocked' || current.relation_version !== task.base_relation_version)
|
|
674
|
+
if ((await this.currentConsensus(current)).lock !== 'unlocked' || current.relation_version !== task.base_relation_version)
|
|
587
675
|
throw ownershipFailure('conflict', 'release target is no longer current');
|
|
588
676
|
}
|
|
589
677
|
else {
|
|
590
678
|
await this.assertBase(task, current);
|
|
591
679
|
if (task.operation === 'transfer')
|
|
592
680
|
await this.requireTransfer(task);
|
|
593
|
-
const target = await this.readOwner(this.targetOwner(task), task.sub_aid);
|
|
594
|
-
if (
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
681
|
+
const target = task.operation === 'bind' && task.stage ? undefined : await this.readOwner(this.targetOwner(task), task.sub_aid);
|
|
682
|
+
if (target) {
|
|
683
|
+
if (!target.exists)
|
|
684
|
+
throw ownershipFailure('unavailable', 'target owner declaration is missing', true);
|
|
685
|
+
const declaration = await this.verifyFile(target.content, 'owner', task.sub_aid, this.targetOwner(task));
|
|
686
|
+
const savedOwner = task.files.owner;
|
|
687
|
+
if (task.owner_proposal && (target.content !== task.owner_proposal.raw || target.sha256 !== task.owner_proposal.sha256))
|
|
688
|
+
throw ownershipFailure('conflict', 'owner binding proposal changed');
|
|
689
|
+
if (savedOwner && (savedOwner.raw !== target.content || savedOwner.hash !== target.sha256))
|
|
690
|
+
throw ownershipFailure('conflict', 'fixed target owner declaration changed');
|
|
691
|
+
if (declaration.action === 'declare' && declaration.statement.relation_version < task.target_relation_version)
|
|
692
|
+
throw ownershipFailure('unavailable', 'target owner declaration is not ready', true);
|
|
693
|
+
if (declaration.action !== 'declare' || declaration.statement.relation_version !== task.target_relation_version)
|
|
694
|
+
throw ownershipFailure('conflict', 'target owner declaration changed');
|
|
695
|
+
}
|
|
602
696
|
}
|
|
603
697
|
task.assertActive?.();
|
|
604
|
-
const published = await this.deps.submitAgentMdRaw(task.sub_aid, saved.raw, saved.condition, task.assertActive);
|
|
605
|
-
if (
|
|
698
|
+
const published = task.stage && !cleanup ? await this.deps.submitAgentMdRaw(task.sub_aid, saved.raw, saved.condition, task.assertActive, true) : await this.deps.submitAgentMdRaw(task.sub_aid, saved.raw, saved.condition, task.assertActive);
|
|
699
|
+
if (task.stage && !cleanup && (published.stage_supported !== true || published.lock !== 'unlocked' || !(published.pending || published.ownership_status === 'pending')))
|
|
700
|
+
throw ownershipFailure('unsupported_protocol', 'NS did not confirm Ownership Stage', true);
|
|
701
|
+
if (published.content !== saved.raw || published.relation_version !== (cleanup ? 0 : task.target_relation_version) || published.lock !== (cleanup ? 'unlocked' : 'locked') && !(task.operation === 'bind' && !cleanup && published.lock === 'unlocked' && (published.pending || published.ownership_status === 'pending')))
|
|
606
702
|
throw ownershipFailure('unavailable', 'agent.md publication could not be verified', true);
|
|
607
703
|
saved.published_etag = published.etag;
|
|
608
704
|
await task.persist();
|
|
@@ -715,10 +811,12 @@ export class OwnershipStorageAdapter {
|
|
|
715
811
|
await this.call('storage.complete_upload', complete);
|
|
716
812
|
return this.readOwnerMd(ownerAid, subAid);
|
|
717
813
|
}
|
|
718
|
-
async deleteOwnerMd(ownerAid, subAid) {
|
|
814
|
+
async deleteOwnerMd(ownerAid, subAid, expectedVersion) {
|
|
719
815
|
this.requireLocal(ownerAid);
|
|
720
816
|
ownershipAid(subAid, 'sub_aid');
|
|
721
|
-
|
|
817
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion <= 0)
|
|
818
|
+
throw ownershipFailure('unavailable', 'Storage owner.md version is unavailable', true);
|
|
819
|
+
await this.call('storage.delete_object', { owner_aid: ownerAid, bucket: 'default', object_key: `sub_aids/${subAid}/owner.md`, expected_version: expectedVersion });
|
|
722
820
|
if ((await this.readOwnerMd(ownerAid, subAid)).exists)
|
|
723
821
|
throw ownershipFailure('unavailable', 'Storage deletion could not be confirmed', true);
|
|
724
822
|
}
|