xytara 2.2.0 → 2.4.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/RELEASE_NOTES.md CHANGED
@@ -1,17 +1,18 @@
1
- # xytara 2.2.0 Release Notes
1
+ # xytara 2.4.0 Release Notes
2
2
 
3
- `xytara` 2.2.0 is the public machine-commerce program-complete line.
3
+ `xytara` 2.4.0 is the foundation-convergence line for runtime wallet, authority, identity, trust, registry, and participation.
4
4
 
5
5
  Highlights:
6
6
 
7
7
  - direct one-line machine execution with `xytara-run`
8
- - release, comparison, adoption, scenario, and launch packs over HTTP and CLI
9
- - release-center, announcement-pack, and release-candidate surfaces for public launch readiness
10
- - credits-first reusable spend posture
11
- - native settlement-aware runtime inspection
12
- - proof-compatible handoff into `xoonya`
13
- - partner-ready onboarding and launch docs
14
- - explicit runtime durability posture, including Supabase-backed persistence on hosts without persistent disk
8
+ - first-class wallet / ledger / lifecycle / reserve / commit / reversal inspection
9
+ - first-class authority bindings with scoped and bounded contract enforcement
10
+ - first-class machine-identity bindings, review, rotation, and operator bundle surfaces
11
+ - explicit capability-registry, pricing-policy, quote-policy, trust-input, and trust-layer packages
12
+ - multi-operator and external network participation packages with bounded admission flows
13
+ - credits-first reusable spend posture with durable runtime economics state
14
+ - native settlement-aware runtime inspection and proof-compatible handoff into `xoonya`
15
+ - partner-ready onboarding, launch docs, and public example paths remain in place
15
16
 
16
17
  Recommended first checks:
17
18
 
@@ -19,10 +20,15 @@ Recommended first checks:
19
20
  2. `xytara-release --candidate --summary`
20
21
  3. `npm run verify:release-candidate`
21
22
  4. `node examples/partner_launch_walkthrough.js`
22
- 5. inspect `/v1/release-candidate/summary` and `/v1/runtime/durability` on the deployed service
23
+ 5. inspect `/v1/economics/accounts/:account_id/wallet-ledger-bundle`
24
+ 6. inspect `/v1/economics/accounts/:account_id/authority-bundle`
25
+ 7. inspect `/v1/economics/accounts/:account_id/machine-identity-operator-bundle`
26
+ 8. inspect `/v1/capability-registry/package`
27
+ 9. inspect `/v1/economics/accounts/:account_id/network-participation-package`
23
28
 
24
29
  Recommended first docs:
25
30
 
26
31
  - `PROGRAM_COMPLETE_RELEASE.md`
32
+ - `FINAL_CONTRACT.md`
27
33
  - `WHY_XYTARA_XOONYA.md`
28
34
  - `PARTNER_READY_PATH.md`
@@ -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
  };