xytara 2.3.0 → 2.5.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/OPERATIONS_RUNBOOK.md +1 -0
- package/README.md +16 -0
- package/RELEASE_NOTES.md +18 -14
- package/SERVICE_CONTRACT.md +75 -0
- package/START_HERE.md +40 -0
- package/bin/xytara.js +55 -0
- package/index.js +1 -1
- package/lib/a2a_lane_contract.js +104 -0
- package/lib/a2c_lane_contract.js +111 -0
- package/lib/account_auth.js +347 -1
- package/lib/artifact_distribution_lane_contract.js +54 -0
- package/lib/asyncapi_contract.js +150 -0
- package/lib/auth_interop_contract.js +80 -0
- package/lib/capability_registry.js +572 -0
- package/lib/cloudevents_contract.js +80 -0
- package/lib/command_flow.js +20 -1
- package/lib/commerce_authority.js +449 -0
- package/lib/commerce_client.js +32 -0
- package/lib/commerce_economics.js +2168 -2
- package/lib/commerce_identity.js +578 -0
- package/lib/commerce_runtime.js +4 -0
- package/lib/erc8004_lane_contract.js +65 -0
- package/lib/event_system_lane_contract.js +75 -0
- package/lib/feature_control_lane_contract.js +54 -0
- package/lib/framework_lane_contract.js +89 -0
- package/lib/identity_auth.js +175 -0
- package/lib/identity_interop_contract.js +82 -0
- package/lib/integration_matrix_contract.js +93 -0
- package/lib/major_rails_lane_contract.js +90 -0
- package/lib/mcp_lane_contract.js +110 -0
- package/lib/openapi_contract.js +296 -0
- package/lib/protocol_lane_contract.js +114 -0
- package/lib/provenance_lane_contract.js +54 -0
- package/lib/provider_lane_contract.js +72 -0
- package/lib/release_history.js +16 -0
- package/lib/settlement_lane_contract.js +111 -0
- package/lib/shared_signals_lane_contract.js +54 -0
- package/lib/stablecoin_lane_contract.js +76 -0
- package/lib/stripe_mpp_lane_contract.js +93 -0
- package/lib/telemetry_lane_contract.js +54 -0
- package/lib/treasury_lane_contract.js +84 -0
- package/lib/x402_lane_contract.js +118 -0
- package/package.json +5 -3
- package/server.js +1544 -0
package/lib/account_auth.js
CHANGED
|
@@ -44,6 +44,84 @@ function buildCredentialPublicView(credential, includeToken = false) {
|
|
|
44
44
|
return view;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function buildAuthorityBindingPublicView(binding, credential, includeToken = false) {
|
|
48
|
+
if (!binding) return null;
|
|
49
|
+
const view = {
|
|
50
|
+
binding_id: binding.binding_id,
|
|
51
|
+
account_id: binding.account_id,
|
|
52
|
+
status: binding.status,
|
|
53
|
+
authority_kind: binding.authority_kind,
|
|
54
|
+
spend_posture: binding.spend_posture,
|
|
55
|
+
scope: binding.scope,
|
|
56
|
+
authority_scope: ensureArray(binding.authority_scope),
|
|
57
|
+
allowed_consequence_families: ensureArray(binding.allowed_consequence_families),
|
|
58
|
+
consequence_bounds: binding.consequence_bounds || {
|
|
59
|
+
max_commit_units: null,
|
|
60
|
+
max_reserve_units: null,
|
|
61
|
+
max_reversal_units: null
|
|
62
|
+
},
|
|
63
|
+
agent_id: binding.agent_id,
|
|
64
|
+
budget_id: binding.budget_id,
|
|
65
|
+
pack_id: binding.pack_id || null,
|
|
66
|
+
entitlement_id: binding.entitlement_id || null,
|
|
67
|
+
credential_id: binding.credential_id || null,
|
|
68
|
+
issued_by: binding.issued_by || null,
|
|
69
|
+
labels: ensureArray(binding.labels),
|
|
70
|
+
expires_at_iso: binding.expires_at_iso || null,
|
|
71
|
+
rotated_from_binding_id: binding.rotated_from_binding_id || null,
|
|
72
|
+
replaced_by_binding_id: binding.replaced_by_binding_id || null,
|
|
73
|
+
created_at_iso: binding.created_at_iso,
|
|
74
|
+
updated_at_iso: binding.updated_at_iso,
|
|
75
|
+
revoked_at_iso: binding.revoked_at_iso || null,
|
|
76
|
+
revoke_reason: binding.revoke_reason || null,
|
|
77
|
+
spend_credential: buildCredentialPublicView(credential, includeToken)
|
|
78
|
+
};
|
|
79
|
+
return view;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function buildAuthorityBindingContractSummary(binding, credential) {
|
|
83
|
+
if (!binding) return null;
|
|
84
|
+
const publicView = buildAuthorityBindingPublicView(binding, credential, false);
|
|
85
|
+
return {
|
|
86
|
+
summary_version: "xytara-authority-binding-contract-summary-v1",
|
|
87
|
+
binding_id: binding.binding_id,
|
|
88
|
+
account_id: binding.account_id,
|
|
89
|
+
authority_kind: binding.authority_kind,
|
|
90
|
+
spend_posture: binding.spend_posture,
|
|
91
|
+
authority_scope: ensureArray(binding.authority_scope),
|
|
92
|
+
allowed_consequence_families: ensureArray(binding.allowed_consequence_families),
|
|
93
|
+
consequence_bounds: publicView.consequence_bounds,
|
|
94
|
+
linked_credential_id: binding.credential_id || null,
|
|
95
|
+
contract_state: binding.status === "active" ? "active_contract" : "inactive_contract",
|
|
96
|
+
linked_surfaces: {
|
|
97
|
+
binding_ref: `/v1/account-auth/authority-bindings/${encodeURIComponent(binding.binding_id)}`,
|
|
98
|
+
spend_credential_ref: binding.credential_id ? `/v1/account-auth/spend-credentials/${encodeURIComponent(binding.credential_id)}` : null
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function buildAuthorityBindingRotationSummary(binding, credential) {
|
|
104
|
+
if (!binding) return null;
|
|
105
|
+
const active = binding.status === "active";
|
|
106
|
+
return {
|
|
107
|
+
summary_version: "xytara-authority-binding-rotation-summary-v1",
|
|
108
|
+
binding_id: binding.binding_id,
|
|
109
|
+
account_id: binding.account_id,
|
|
110
|
+
status: binding.status,
|
|
111
|
+
renewable_state: active ? "renewable" : "inactive",
|
|
112
|
+
rotatable_state: active ? "rotatable" : "inactive",
|
|
113
|
+
expires_at_iso: binding.expires_at_iso || null,
|
|
114
|
+
rotated_from_binding_id: binding.rotated_from_binding_id || null,
|
|
115
|
+
replaced_by_binding_id: binding.replaced_by_binding_id || null,
|
|
116
|
+
linked_credential_id: binding.credential_id || null,
|
|
117
|
+
linked_surfaces: {
|
|
118
|
+
binding_ref: `/v1/account-auth/authority-bindings/${encodeURIComponent(binding.binding_id)}`,
|
|
119
|
+
contract_summary_ref: `/v1/account-auth/authority-bindings/${encodeURIComponent(binding.binding_id)}/contract-summary`,
|
|
120
|
+
spend_credential_ref: binding.credential_id ? `/v1/account-auth/spend-credentials/${encodeURIComponent(binding.credential_id)}` : null
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
47
125
|
function isCredentialExpired(credential) {
|
|
48
126
|
if (!credential || !credential.expires_at_iso) return false;
|
|
49
127
|
const expiresAt = Date.parse(credential.expires_at_iso);
|
|
@@ -84,6 +162,57 @@ function createSpendCredential(state, body) {
|
|
|
84
162
|
return buildCredentialPublicView(credential, true);
|
|
85
163
|
}
|
|
86
164
|
|
|
165
|
+
function createAuthorityBinding(state, body) {
|
|
166
|
+
const payload = ensureObject(body);
|
|
167
|
+
const bindingId = normalizeString(payload.binding_id, `authority_binding_${state.accountAuthorityBindings.size + 1}`);
|
|
168
|
+
const credential = createSpendCredential(state, {
|
|
169
|
+
credential_id: normalizeString(payload.credential_id, `spend_for_${bindingId}`),
|
|
170
|
+
bearer_token: normalizeString(payload.bearer_token, null),
|
|
171
|
+
account_id: normalizeString(payload.account_id, "acct_demo"),
|
|
172
|
+
agent_id: normalizeString(payload.agent_id, null),
|
|
173
|
+
budget_id: normalizeString(payload.budget_id, null),
|
|
174
|
+
pack_id: normalizeString(payload.pack_id, null),
|
|
175
|
+
entitlement_id: normalizeString(payload.entitlement_id, null),
|
|
176
|
+
scope: normalizeString(payload.scope, "runtime_spend"),
|
|
177
|
+
labels: ensureArray(payload.labels),
|
|
178
|
+
status: normalizeString(payload.status, "active"),
|
|
179
|
+
issued_by: normalizeString(payload.issued_by, "operator"),
|
|
180
|
+
expires_at_iso: normalizeString(payload.expires_at_iso, null)
|
|
181
|
+
});
|
|
182
|
+
const createdAtIso = nowIso();
|
|
183
|
+
const binding = {
|
|
184
|
+
binding_id: bindingId,
|
|
185
|
+
account_id: credential.account_id,
|
|
186
|
+
credential_id: credential.credential_id,
|
|
187
|
+
authority_kind: normalizeString(payload.authority_kind, "delegated_runtime_spend"),
|
|
188
|
+
spend_posture: credential.spend_posture,
|
|
189
|
+
scope: credential.scope,
|
|
190
|
+
authority_scope: ensureArray(payload.authority_scope).map((value) => String(value || "").trim()).filter(Boolean),
|
|
191
|
+
allowed_consequence_families: ensureArray(payload.allowed_consequence_families).map((value) => String(value || "").trim()).filter(Boolean),
|
|
192
|
+
consequence_bounds: {
|
|
193
|
+
max_commit_units: Number.isFinite(Number(payload.max_commit_units)) ? Number(payload.max_commit_units) : null,
|
|
194
|
+
max_reserve_units: Number.isFinite(Number(payload.max_reserve_units)) ? Number(payload.max_reserve_units) : null,
|
|
195
|
+
max_reversal_units: Number.isFinite(Number(payload.max_reversal_units)) ? Number(payload.max_reversal_units) : null
|
|
196
|
+
},
|
|
197
|
+
agent_id: credential.agent_id,
|
|
198
|
+
budget_id: credential.budget_id,
|
|
199
|
+
pack_id: credential.pack_id || null,
|
|
200
|
+
entitlement_id: credential.entitlement_id || null,
|
|
201
|
+
status: normalizeString(payload.status, "active"),
|
|
202
|
+
issued_by: normalizeString(payload.issued_by, "operator"),
|
|
203
|
+
labels: ensureArray(payload.labels),
|
|
204
|
+
expires_at_iso: credential.expires_at_iso,
|
|
205
|
+
rotated_from_binding_id: normalizeString(payload.rotated_from_binding_id, null),
|
|
206
|
+
replaced_by_binding_id: normalizeString(payload.replaced_by_binding_id, null),
|
|
207
|
+
created_at_iso: createdAtIso,
|
|
208
|
+
updated_at_iso: createdAtIso,
|
|
209
|
+
revoked_at_iso: null,
|
|
210
|
+
revoke_reason: null
|
|
211
|
+
};
|
|
212
|
+
state.accountAuthorityBindings.set(bindingId, binding);
|
|
213
|
+
return buildAuthorityBindingPublicView(binding, state.accountSpendCredentials.get(credential.credential_id), true);
|
|
214
|
+
}
|
|
215
|
+
|
|
87
216
|
function listSpendCredentials(state, filters) {
|
|
88
217
|
const payload = ensureObject(filters);
|
|
89
218
|
const accountId = normalizeString(payload.account_id, null);
|
|
@@ -102,6 +231,116 @@ function getSpendCredential(state, credentialId) {
|
|
|
102
231
|
return buildCredentialPublicView(state.accountSpendCredentials.get(credentialId), false);
|
|
103
232
|
}
|
|
104
233
|
|
|
234
|
+
function listAuthorityBindings(state, filters) {
|
|
235
|
+
const payload = ensureObject(filters);
|
|
236
|
+
const accountId = normalizeString(payload.account_id, null);
|
|
237
|
+
const status = normalizeString(payload.status, null);
|
|
238
|
+
return Array.from(state.accountAuthorityBindings.values())
|
|
239
|
+
.filter((binding) => {
|
|
240
|
+
if (accountId && binding.account_id !== accountId) return false;
|
|
241
|
+
if (status && binding.status !== status) return false;
|
|
242
|
+
return true;
|
|
243
|
+
})
|
|
244
|
+
.map((binding) => buildAuthorityBindingPublicView(binding, state.accountSpendCredentials.get(binding.credential_id), false));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function getAuthorityBinding(state, bindingId) {
|
|
248
|
+
if (!bindingId || !state.accountAuthorityBindings.has(bindingId)) return null;
|
|
249
|
+
const binding = state.accountAuthorityBindings.get(bindingId);
|
|
250
|
+
return buildAuthorityBindingPublicView(binding, state.accountSpendCredentials.get(binding.credential_id), false);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function getAuthorityBindingContractSummary(state, bindingId) {
|
|
254
|
+
if (!bindingId || !state.accountAuthorityBindings.has(bindingId)) return null;
|
|
255
|
+
const binding = state.accountAuthorityBindings.get(bindingId);
|
|
256
|
+
return buildAuthorityBindingContractSummary(binding, state.accountSpendCredentials.get(binding.credential_id));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function getAuthorityBindingRotationSummary(state, bindingId) {
|
|
260
|
+
if (!bindingId || !state.accountAuthorityBindings.has(bindingId)) return null;
|
|
261
|
+
const binding = state.accountAuthorityBindings.get(bindingId);
|
|
262
|
+
return buildAuthorityBindingRotationSummary(binding, state.accountSpendCredentials.get(binding.credential_id));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function evaluateAuthorityBindingAction(binding, action, units) {
|
|
266
|
+
const target = binding && typeof binding === "object" ? binding : null;
|
|
267
|
+
const numericUnits = Number.isFinite(Number(units)) ? Number(units) : 0;
|
|
268
|
+
const allowedScopes = target ? ensureArray(target.authority_scope) : [];
|
|
269
|
+
const allowedFamilies = target ? ensureArray(target.allowed_consequence_families) : [];
|
|
270
|
+
const bounds = target && target.consequence_bounds ? target.consequence_bounds : {};
|
|
271
|
+
|
|
272
|
+
if (!target) {
|
|
273
|
+
return { ok: true };
|
|
274
|
+
}
|
|
275
|
+
if (target.status !== "active") {
|
|
276
|
+
return { ok: false, reason: "authority_binding_inactive", binding_id: target.binding_id };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const scopeMap = {
|
|
280
|
+
delegated_credit_spend: "runtime.execute",
|
|
281
|
+
reserve: "economics.reserve",
|
|
282
|
+
release: "economics.release",
|
|
283
|
+
reverse: "economics.reverse"
|
|
284
|
+
};
|
|
285
|
+
const familyMap = {
|
|
286
|
+
delegated_credit_spend: "commit",
|
|
287
|
+
reserve: "reserve",
|
|
288
|
+
release: "release",
|
|
289
|
+
reverse: "reverse"
|
|
290
|
+
};
|
|
291
|
+
const boundKeyMap = {
|
|
292
|
+
delegated_credit_spend: "max_commit_units",
|
|
293
|
+
reserve: "max_reserve_units",
|
|
294
|
+
reverse: "max_reversal_units"
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const requiredScope = scopeMap[action] || null;
|
|
298
|
+
if (requiredScope && allowedScopes.length > 0 && !allowedScopes.includes(requiredScope)) {
|
|
299
|
+
return {
|
|
300
|
+
ok: false,
|
|
301
|
+
reason: "authority_scope_not_allowed",
|
|
302
|
+
binding_id: target.binding_id,
|
|
303
|
+
required_scope: requiredScope,
|
|
304
|
+
authority_scope: allowedScopes
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const requiredFamily = familyMap[action] || null;
|
|
309
|
+
if (requiredFamily && allowedFamilies.length > 0 && !allowedFamilies.includes(requiredFamily)) {
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
reason: "authority_consequence_family_not_allowed",
|
|
313
|
+
binding_id: target.binding_id,
|
|
314
|
+
required_consequence_family: requiredFamily,
|
|
315
|
+
allowed_consequence_families: allowedFamilies
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const boundKey = boundKeyMap[action] || null;
|
|
320
|
+
if (boundKey && Number.isFinite(Number(bounds[boundKey])) && numericUnits > Number(bounds[boundKey])) {
|
|
321
|
+
return {
|
|
322
|
+
ok: false,
|
|
323
|
+
reason: "authority_consequence_bound_exceeded",
|
|
324
|
+
binding_id: target.binding_id,
|
|
325
|
+
bound_key: boundKey,
|
|
326
|
+
max_units: Number(bounds[boundKey]),
|
|
327
|
+
attempted_units: numericUnits
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
ok: true,
|
|
333
|
+
binding_id: target.binding_id,
|
|
334
|
+
authority_scope: allowedScopes,
|
|
335
|
+
allowed_consequence_families: allowedFamilies,
|
|
336
|
+
consequence_bounds: {
|
|
337
|
+
max_commit_units: Number.isFinite(Number(bounds.max_commit_units)) ? Number(bounds.max_commit_units) : null,
|
|
338
|
+
max_reserve_units: Number.isFinite(Number(bounds.max_reserve_units)) ? Number(bounds.max_reserve_units) : null,
|
|
339
|
+
max_reversal_units: Number.isFinite(Number(bounds.max_reversal_units)) ? Number(bounds.max_reversal_units) : null
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
105
344
|
function revokeSpendCredential(state, credentialId, body) {
|
|
106
345
|
if (!credentialId || !state.accountSpendCredentials.has(credentialId)) return null;
|
|
107
346
|
const payload = ensureObject(body);
|
|
@@ -117,6 +356,94 @@ function revokeSpendCredential(state, credentialId, body) {
|
|
|
117
356
|
return buildCredentialPublicView(next, false);
|
|
118
357
|
}
|
|
119
358
|
|
|
359
|
+
function revokeAuthorityBinding(state, bindingId, body) {
|
|
360
|
+
if (!bindingId || !state.accountAuthorityBindings.has(bindingId)) return null;
|
|
361
|
+
const payload = ensureObject(body);
|
|
362
|
+
const current = state.accountAuthorityBindings.get(bindingId);
|
|
363
|
+
const next = {
|
|
364
|
+
...current,
|
|
365
|
+
status: "revoked",
|
|
366
|
+
revoked_at_iso: nowIso(),
|
|
367
|
+
revoke_reason: normalizeString(payload.reason, "operator_revoked"),
|
|
368
|
+
updated_at_iso: nowIso()
|
|
369
|
+
};
|
|
370
|
+
state.accountAuthorityBindings.set(bindingId, next);
|
|
371
|
+
if (current.credential_id) {
|
|
372
|
+
revokeSpendCredential(state, current.credential_id, payload);
|
|
373
|
+
}
|
|
374
|
+
return buildAuthorityBindingPublicView(next, current.credential_id ? state.accountSpendCredentials.get(current.credential_id) : null, false);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function renewAuthorityBinding(state, bindingId, body) {
|
|
378
|
+
if (!bindingId || !state.accountAuthorityBindings.has(bindingId)) return null;
|
|
379
|
+
const payload = ensureObject(body);
|
|
380
|
+
const current = state.accountAuthorityBindings.get(bindingId);
|
|
381
|
+
const nextExpiresAtIso = normalizeString(payload.expires_at_iso, current.expires_at_iso || null);
|
|
382
|
+
const updatedAtIso = nowIso();
|
|
383
|
+
const next = {
|
|
384
|
+
...current,
|
|
385
|
+
expires_at_iso: nextExpiresAtIso,
|
|
386
|
+
updated_at_iso: updatedAtIso
|
|
387
|
+
};
|
|
388
|
+
state.accountAuthorityBindings.set(bindingId, next);
|
|
389
|
+
if (current.credential_id && state.accountSpendCredentials.has(current.credential_id)) {
|
|
390
|
+
const credential = state.accountSpendCredentials.get(current.credential_id);
|
|
391
|
+
state.accountSpendCredentials.set(current.credential_id, {
|
|
392
|
+
...credential,
|
|
393
|
+
expires_at_iso: nextExpiresAtIso,
|
|
394
|
+
updated_at_iso: updatedAtIso
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
return buildAuthorityBindingPublicView(next, current.credential_id ? state.accountSpendCredentials.get(current.credential_id) : null, false);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function rotateAuthorityBinding(state, bindingId, body) {
|
|
401
|
+
if (!bindingId || !state.accountAuthorityBindings.has(bindingId)) return null;
|
|
402
|
+
const payload = ensureObject(body);
|
|
403
|
+
const current = state.accountAuthorityBindings.get(bindingId);
|
|
404
|
+
const currentCredential = current.credential_id ? state.accountSpendCredentials.get(current.credential_id) : null;
|
|
405
|
+
const successorBindingId = normalizeString(payload.successor_binding_id, `${bindingId}_rotated`);
|
|
406
|
+
const successorCredentialId = normalizeString(payload.successor_credential_id, current.credential_id ? `${current.credential_id}_rotated` : `spend_for_${successorBindingId}`);
|
|
407
|
+
const successor = createAuthorityBinding(state, {
|
|
408
|
+
binding_id: successorBindingId,
|
|
409
|
+
credential_id: successorCredentialId,
|
|
410
|
+
bearer_token: normalizeString(payload.bearer_token, null),
|
|
411
|
+
account_id: current.account_id,
|
|
412
|
+
agent_id: normalizeString(payload.agent_id, current.agent_id),
|
|
413
|
+
budget_id: normalizeString(payload.budget_id, current.budget_id),
|
|
414
|
+
pack_id: normalizeString(payload.pack_id, current.pack_id),
|
|
415
|
+
entitlement_id: normalizeString(payload.entitlement_id, current.entitlement_id),
|
|
416
|
+
scope: normalizeString(payload.scope, current.scope),
|
|
417
|
+
authority_kind: normalizeString(payload.authority_kind, current.authority_kind),
|
|
418
|
+
authority_scope: ensureArray(payload.authority_scope).length > 0 ? ensureArray(payload.authority_scope) : ensureArray(current.authority_scope),
|
|
419
|
+
allowed_consequence_families: ensureArray(payload.allowed_consequence_families).length > 0 ? ensureArray(payload.allowed_consequence_families) : ensureArray(current.allowed_consequence_families),
|
|
420
|
+
max_commit_units: Number.isFinite(Number(payload.max_commit_units)) ? Number(payload.max_commit_units) : current.consequence_bounds.max_commit_units,
|
|
421
|
+
max_reserve_units: Number.isFinite(Number(payload.max_reserve_units)) ? Number(payload.max_reserve_units) : current.consequence_bounds.max_reserve_units,
|
|
422
|
+
max_reversal_units: Number.isFinite(Number(payload.max_reversal_units)) ? Number(payload.max_reversal_units) : current.consequence_bounds.max_reversal_units,
|
|
423
|
+
labels: ensureArray(payload.labels).length > 0 ? ensureArray(payload.labels) : ensureArray(current.labels),
|
|
424
|
+
issued_by: normalizeString(payload.issued_by, current.issued_by || "operator"),
|
|
425
|
+
expires_at_iso: normalizeString(payload.expires_at_iso, current.expires_at_iso || (currentCredential ? currentCredential.expires_at_iso : null)),
|
|
426
|
+
rotated_from_binding_id: current.binding_id
|
|
427
|
+
});
|
|
428
|
+
const revoked = revokeAuthorityBinding(state, bindingId, {
|
|
429
|
+
reason: normalizeString(payload.reason, "rotated_to_successor")
|
|
430
|
+
});
|
|
431
|
+
const successorRecord = state.accountAuthorityBindings.get(successor.binding_id);
|
|
432
|
+
state.accountAuthorityBindings.set(successor.binding_id, {
|
|
433
|
+
...successorRecord,
|
|
434
|
+
rotated_from_binding_id: current.binding_id
|
|
435
|
+
});
|
|
436
|
+
state.accountAuthorityBindings.set(bindingId, {
|
|
437
|
+
...state.accountAuthorityBindings.get(bindingId),
|
|
438
|
+
replaced_by_binding_id: successor.binding_id
|
|
439
|
+
});
|
|
440
|
+
return {
|
|
441
|
+
rotated_binding: buildAuthorityBindingPublicView(state.accountAuthorityBindings.get(bindingId), current.credential_id ? state.accountSpendCredentials.get(current.credential_id) : null, false),
|
|
442
|
+
successor_authority_binding: buildAuthorityBindingPublicView(state.accountAuthorityBindings.get(successor.binding_id), state.accountSpendCredentials.get(successor.credential_id), true),
|
|
443
|
+
previous_view: revoked
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
120
447
|
function resolveSpendCredential(state, bearerToken) {
|
|
121
448
|
const token = normalizeString(bearerToken, null);
|
|
122
449
|
if (!token) {
|
|
@@ -147,26 +474,45 @@ function resolveSpendCredential(state, bearerToken) {
|
|
|
147
474
|
credential: buildCredentialPublicView(credential, false)
|
|
148
475
|
};
|
|
149
476
|
}
|
|
477
|
+
const binding = Array.from(state.accountAuthorityBindings.values()).find((entry) => entry && entry.credential_id === credentialId && entry.status === "active") || null;
|
|
150
478
|
return {
|
|
151
479
|
ok: true,
|
|
152
480
|
credential,
|
|
481
|
+
binding,
|
|
153
482
|
authorization_context: {
|
|
154
483
|
verification_mode: "delegated_spend_credential",
|
|
155
484
|
wallet_id: credential.credential_id,
|
|
156
485
|
payment_payload: {
|
|
486
|
+
binding_id: binding ? binding.binding_id : null,
|
|
157
487
|
credential_id: credential.credential_id,
|
|
158
488
|
spend_posture: credential.spend_posture,
|
|
159
489
|
pack_id: credential.pack_id || null,
|
|
160
|
-
entitlement_id: credential.entitlement_id || null
|
|
490
|
+
entitlement_id: credential.entitlement_id || null,
|
|
491
|
+
authority_scope: binding ? ensureArray(binding.authority_scope) : [],
|
|
492
|
+
allowed_consequence_families: binding ? ensureArray(binding.allowed_consequence_families) : [],
|
|
493
|
+
consequence_bounds: binding && binding.consequence_bounds ? binding.consequence_bounds : {
|
|
494
|
+
max_commit_units: null,
|
|
495
|
+
max_reserve_units: null,
|
|
496
|
+
max_reversal_units: null
|
|
497
|
+
}
|
|
161
498
|
}
|
|
162
499
|
}
|
|
163
500
|
};
|
|
164
501
|
}
|
|
165
502
|
|
|
166
503
|
module.exports = {
|
|
504
|
+
createAuthorityBinding,
|
|
167
505
|
createSpendCredential,
|
|
506
|
+
evaluateAuthorityBindingAction,
|
|
507
|
+
getAuthorityBinding,
|
|
508
|
+
getAuthorityBindingContractSummary,
|
|
509
|
+
getAuthorityBindingRotationSummary,
|
|
168
510
|
getSpendCredential,
|
|
511
|
+
listAuthorityBindings,
|
|
169
512
|
listSpendCredentials,
|
|
513
|
+
renewAuthorityBinding,
|
|
170
514
|
resolveSpendCredential,
|
|
515
|
+
rotateAuthorityBinding,
|
|
516
|
+
revokeAuthorityBinding,
|
|
171
517
|
revokeSpendCredential
|
|
172
518
|
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
function buildArtifactDistributionLanePack() {
|
|
4
|
+
return {
|
|
5
|
+
product: "xytara",
|
|
6
|
+
category: "machine-commerce-artifact-distribution-lane-pack",
|
|
7
|
+
pack_version: "xytara-artifact-distribution-lane-pack-v1",
|
|
8
|
+
lane_state: "first_party_artifact_distribution_lane_present",
|
|
9
|
+
posture: "oci_style_distribution_and_export_lane",
|
|
10
|
+
standards: ["oci_artifacts", "oras_style_distribution"],
|
|
11
|
+
artifact_families: ["adapter_packs", "submission_bundles", "registry_snapshots", "release_artifacts"],
|
|
12
|
+
supported_surfaces: {
|
|
13
|
+
integrations_ref: "/v1/integrations",
|
|
14
|
+
integration_snapshot_ref: "/v1/integrations/review/registry-snapshot",
|
|
15
|
+
adapter_pack_ref: "/v1/adapter-pack",
|
|
16
|
+
release_center_ref: "/v1/release-center",
|
|
17
|
+
release_pack_ref: "/v1/release-pack"
|
|
18
|
+
},
|
|
19
|
+
first_run_flows: [
|
|
20
|
+
{
|
|
21
|
+
flow_ref: "artifact_distribution_alignment",
|
|
22
|
+
recommended_reason: "best path for teams that want portable adapter, registry, and release artifacts instead of ad hoc zip-and-doc distribution",
|
|
23
|
+
sequence: [
|
|
24
|
+
"inspect_artifact_distribution_lane_summary",
|
|
25
|
+
"inspect_adapter_and_registry_export_surfaces",
|
|
26
|
+
"treat_release_and_submission bundles as distribution-ready artifacts",
|
|
27
|
+
"publish_or_transfer_artifacts through standard registries later without changing canonical shapes"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
guardrails: [
|
|
32
|
+
"artifact portability should preserve canonical bundle shapes instead of inventing a second artifact model",
|
|
33
|
+
"distribution posture should remain subordinate to runtime, proof, and integration truth"
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function summarizeArtifactDistributionLanePack() {
|
|
39
|
+
const pack = buildArtifactDistributionLanePack();
|
|
40
|
+
return {
|
|
41
|
+
product: "xytara",
|
|
42
|
+
category: "machine-commerce-artifact-distribution-lane-pack-summary",
|
|
43
|
+
summary_version: "xytara-artifact-distribution-lane-pack-summary-v1",
|
|
44
|
+
lane_state: pack.lane_state,
|
|
45
|
+
standard_count: pack.standards.length,
|
|
46
|
+
artifact_family_count: pack.artifact_families.length,
|
|
47
|
+
linked_surfaces: pack.supported_surfaces
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
buildArtifactDistributionLanePack,
|
|
53
|
+
summarizeArtifactDistributionLanePack
|
|
54
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const pkg = require("../package.json");
|
|
4
|
+
|
|
5
|
+
function buildAsyncApiDocument() {
|
|
6
|
+
return {
|
|
7
|
+
asyncapi: "3.0.0",
|
|
8
|
+
info: {
|
|
9
|
+
title: "xytara Event Contract",
|
|
10
|
+
version: pkg.version,
|
|
11
|
+
summary: "Machine-commerce runtime event and handoff contract.",
|
|
12
|
+
description: "This AsyncAPI document describes the stable runtime event and handoff surfaces that outside builders and partners should rely on first."
|
|
13
|
+
},
|
|
14
|
+
servers: {
|
|
15
|
+
httpRuntime: {
|
|
16
|
+
host: "127.0.0.1:4320",
|
|
17
|
+
protocol: "http",
|
|
18
|
+
description: "Local xytara HTTP event and handoff entrypoint"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
channels: {
|
|
22
|
+
"runtime/events/emit": {
|
|
23
|
+
address: "/v1/runtime/emit",
|
|
24
|
+
messages: {
|
|
25
|
+
runtimeEmitRequest: {
|
|
26
|
+
name: "runtimeEmitRequest",
|
|
27
|
+
title: "Runtime emit request",
|
|
28
|
+
summary: "Append a runtime event record."
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"runtime/events/anchor": {
|
|
33
|
+
address: "/v1/runtime/anchor",
|
|
34
|
+
messages: {
|
|
35
|
+
runtimeAnchorRequest: {
|
|
36
|
+
name: "runtimeAnchorRequest",
|
|
37
|
+
title: "Runtime anchor request",
|
|
38
|
+
summary: "Anchor a runtime event into registry/anchor posture."
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"runtime/events/emit-anchor": {
|
|
43
|
+
address: "/v1/runtime/emit-anchor",
|
|
44
|
+
messages: {
|
|
45
|
+
runtimeEmitAnchorRequest: {
|
|
46
|
+
name: "runtimeEmitAnchorRequest",
|
|
47
|
+
title: "Runtime emit-anchor request",
|
|
48
|
+
summary: "Emit and anchor a runtime event in one call."
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"handoffs/trust/emit": {
|
|
53
|
+
address: "/v1/trust/handoffs/emit",
|
|
54
|
+
messages: {
|
|
55
|
+
trustHandoffEmitRequest: {
|
|
56
|
+
name: "trustHandoffEmitRequest",
|
|
57
|
+
title: "Trust handoff emit request",
|
|
58
|
+
summary: "Emit a trust-compatible handoff bundle."
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"handoffs/execution-receipts/emit": {
|
|
63
|
+
address: "/v1/execution-receipts/handoffs/emit",
|
|
64
|
+
messages: {
|
|
65
|
+
executionReceiptHandoffEmitRequest: {
|
|
66
|
+
name: "executionReceiptHandoffEmitRequest",
|
|
67
|
+
title: "Execution receipt handoff emit request",
|
|
68
|
+
summary: "Emit an execution receipt handoff bundle."
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"handoffs/receipt-ledger/emit": {
|
|
73
|
+
address: "/v1/receipt-ledger/handoffs/emit",
|
|
74
|
+
messages: {
|
|
75
|
+
receiptLedgerHandoffEmitRequest: {
|
|
76
|
+
name: "receiptLedgerHandoffEmitRequest",
|
|
77
|
+
title: "Receipt ledger handoff emit request",
|
|
78
|
+
summary: "Emit a receipt-ledger handoff bundle."
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
operations: {
|
|
84
|
+
publishRuntimeEvent: {
|
|
85
|
+
action: "send",
|
|
86
|
+
channel: { $ref: "#/channels/runtime/events/emit" },
|
|
87
|
+
summary: "Publish runtime event data through the stable emit surface."
|
|
88
|
+
},
|
|
89
|
+
publishRuntimeAnchor: {
|
|
90
|
+
action: "send",
|
|
91
|
+
channel: { $ref: "#/channels/runtime/events/anchor" },
|
|
92
|
+
summary: "Publish anchoring data through the stable anchor surface."
|
|
93
|
+
},
|
|
94
|
+
publishRuntimeEmitAnchor: {
|
|
95
|
+
action: "send",
|
|
96
|
+
channel: { $ref: "#/channels/runtime/events/emit-anchor" },
|
|
97
|
+
summary: "Publish combined emit-anchor data through the stable combined surface."
|
|
98
|
+
},
|
|
99
|
+
publishTrustHandoff: {
|
|
100
|
+
action: "send",
|
|
101
|
+
channel: { $ref: "#/channels/handoffs/trust/emit" },
|
|
102
|
+
summary: "Publish trust handoff data for proof followthrough."
|
|
103
|
+
},
|
|
104
|
+
publishExecutionReceiptHandoff: {
|
|
105
|
+
action: "send",
|
|
106
|
+
channel: { $ref: "#/channels/handoffs/execution-receipts/emit" },
|
|
107
|
+
summary: "Publish execution receipt handoff data."
|
|
108
|
+
},
|
|
109
|
+
publishReceiptLedgerHandoff: {
|
|
110
|
+
action: "send",
|
|
111
|
+
channel: { $ref: "#/channels/handoffs/receipt-ledger/emit" },
|
|
112
|
+
summary: "Publish receipt-ledger handoff data."
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"x-naxytra-contract": {
|
|
116
|
+
product: "xytara",
|
|
117
|
+
stability: "stable_public_event_layer",
|
|
118
|
+
channel_count: 6,
|
|
119
|
+
linked_docs: [
|
|
120
|
+
"SERVICE_CONTRACT.md",
|
|
121
|
+
"FINAL_CONTRACT.md",
|
|
122
|
+
"START_HERE.md"
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function summarizeAsyncApiDocument() {
|
|
129
|
+
const document = buildAsyncApiDocument();
|
|
130
|
+
return {
|
|
131
|
+
product: "xytara",
|
|
132
|
+
category: "machine-commerce-asyncapi-contract-summary",
|
|
133
|
+
summary_version: "xytara-asyncapi-contract-summary-v1",
|
|
134
|
+
asyncapi_version: document.asyncapi,
|
|
135
|
+
info_version: document.info.version,
|
|
136
|
+
channel_count: Object.keys(document.channels).length,
|
|
137
|
+
operation_count: Object.keys(document.operations).length,
|
|
138
|
+
primary_event_lanes: ["runtime", "handoff"],
|
|
139
|
+
linked_surfaces: {
|
|
140
|
+
asyncapi_ref: "/asyncapi.json",
|
|
141
|
+
service_contract_ref: "SERVICE_CONTRACT.md",
|
|
142
|
+
openapi_ref: "/openapi.json"
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
buildAsyncApiDocument,
|
|
149
|
+
summarizeAsyncApiDocument
|
|
150
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const pkg = require("../package.json");
|
|
4
|
+
|
|
5
|
+
function buildAuthInteropContract() {
|
|
6
|
+
return {
|
|
7
|
+
product: "xytara",
|
|
8
|
+
category: "machine-commerce-auth-interop-contract",
|
|
9
|
+
contract_version: "xytara-auth-interop-contract-v1",
|
|
10
|
+
service_version: pkg.version,
|
|
11
|
+
primary_posture: "native_authority_with_oauth_oidc_token_exchange_interop",
|
|
12
|
+
supported_interop_profiles: [
|
|
13
|
+
{
|
|
14
|
+
profile_id: "oauth_client_credentials_runtime",
|
|
15
|
+
standards: ["oauth_2_0", "oidc_optional"],
|
|
16
|
+
intended_use: "machine-to-machine runtime invocation",
|
|
17
|
+
primary_routes: ["/v1/commands/execute", "/v1/mcp/tools/invoke"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
profile_id: "bounded_delegation_token_exchange",
|
|
21
|
+
standards: ["oauth_2_0_token_exchange", "jwt_bearer_optional"],
|
|
22
|
+
intended_use: "map upstream bearer posture into bounded delegated authority",
|
|
23
|
+
primary_routes: [
|
|
24
|
+
"/v1/account-auth/spend-credentials",
|
|
25
|
+
"/v1/account-auth/authority-bindings",
|
|
26
|
+
"/v1/commands/execute"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
profile_id: "mcp_a2a_a2c_interop_auth",
|
|
31
|
+
standards: ["oauth_2_0", "oidc", "token_exchange_optional"],
|
|
32
|
+
intended_use: "protocol-lane authentication for MCP, A2A, and A2C usage",
|
|
33
|
+
primary_routes: ["/v1/mcp/tools/invoke", "/x402/mcp/tools/invoke", "/v1/commands/execute"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
profile_id: "x402_payment_plus_bounded_auth",
|
|
37
|
+
standards: ["oauth_2_0_optional", "x402"],
|
|
38
|
+
intended_use: "combine payment challenge posture with bounded authenticated execution",
|
|
39
|
+
primary_routes: ["/x402/mcp/tools/invoke", "/x402/commands/execute"]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
native_authority_mapping: {
|
|
43
|
+
authority_bindings: "/v1/account-auth/authority-bindings",
|
|
44
|
+
spend_credentials: "/v1/account-auth/spend-credentials",
|
|
45
|
+
execution_entry: "/v1/commands/execute",
|
|
46
|
+
mcp_entry: "/v1/mcp/tools/invoke"
|
|
47
|
+
},
|
|
48
|
+
guardrails: [
|
|
49
|
+
"native authority bindings remain canonical for bounded execution",
|
|
50
|
+
"oauth or oidc interop must not replace native consequence bounds",
|
|
51
|
+
"token exchange may map into delegation but must not bypass authority contracts",
|
|
52
|
+
"payment verification and auth posture remain separate concerns even when combined in one flow"
|
|
53
|
+
],
|
|
54
|
+
linked_surfaces: {
|
|
55
|
+
openapi_ref: "/openapi.json",
|
|
56
|
+
asyncapi_ref: "/asyncapi.json",
|
|
57
|
+
cloudevents_ref: "/cloudevents.json",
|
|
58
|
+
service_contract_ref: "SERVICE_CONTRACT.md"
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function summarizeAuthInteropContract() {
|
|
64
|
+
const contract = buildAuthInteropContract();
|
|
65
|
+
return {
|
|
66
|
+
product: "xytara",
|
|
67
|
+
category: "machine-commerce-auth-interop-contract-summary",
|
|
68
|
+
summary_version: "xytara-auth-interop-contract-summary-v1",
|
|
69
|
+
contract_version: contract.contract_version,
|
|
70
|
+
profile_count: contract.supported_interop_profiles.length,
|
|
71
|
+
primary_posture: contract.primary_posture,
|
|
72
|
+
primary_protocol_lanes: ["mcp", "a2a", "a2c", "x402"],
|
|
73
|
+
linked_surfaces: contract.linked_surfaces
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
buildAuthInteropContract,
|
|
79
|
+
summarizeAuthInteropContract
|
|
80
|
+
};
|