From 706872d28e973ddf3209e42a11cc39f439c97028 Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Thu, 25 Jun 2026 18:35:42 -0400 Subject: [PATCH 1/7] Add isnad-chain trust primitive Introduce verify_isnad_chain: validates a chain of trust transmission from a rooted authority to a terminal subject. Enforces continuity (muttasil), per-link validity, trust floors, and attenuation along the chain, surfacing the weakest link and effective trust. Co-Authored-By: Claude Opus 4.8 --- .gitignore | 1 + docs/concepts/isnad-chains.md | 36 ++++++++++++++++++++++++++++++++ examples/isnad-invalid.json | 1 + examples/isnad-valid.json | 1 + src/index.mjs | 2 +- src/isnad.mjs | 39 +++++++++++++++++++++++++++++++++++ src/types.mjs | 2 +- tests/isnad.test.mjs | 20 ++++++++++++++++++ 8 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 docs/concepts/isnad-chains.md create mode 100644 examples/isnad-invalid.json create mode 100644 examples/isnad-valid.json create mode 100644 src/isnad.mjs create mode 100644 tests/isnad.test.mjs diff --git a/.gitignore b/.gitignore index 18281cf..d509f43 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ node_modules/ dist/ **/dist/ .runtime-authority-receipts.json +.cortextrace/ *.log .DS_Store diff --git a/docs/concepts/isnad-chains.md b/docs/concepts/isnad-chains.md new file mode 100644 index 0000000..eab5189 --- /dev/null +++ b/docs/concepts/isnad-chains.md @@ -0,0 +1,36 @@ +# Isnad Chains + +An isnad chain expresses the **chain of transmission** for trust: an ordered sequence of links carrying authority from a trusted root authority down to a terminal subject. The name follows the classical *isnad* — a chain of narrators whose soundness depends on every link, not just the source. + +`verify_isnad_chain` records that a transmission chain was evaluated for soundness before downstream authority systems rely on the terminal subject. + +## Boundary + +TTP establishes trustworthiness. RAP evaluates authority. Execution Exchange enforces downstream runtime decisions in production. CortexTrace records evidence and receipts. Isnad chains express transmission continuity; they do not enforce execution. + +## Soundness conditions + +A chain is sound (`valid: true`) when: + +* **Rooted** — the first link's issuer is the declared `rootAuthority`. +* **Continuous (muttasil)** — each link's `issuer` equals the previous link's `subject`. Any gap, self-transmission, or non-transferable intermediate breaks the chain. +* **Each link is valid** — unexpired, in scope for the requested action, issued by a trusted narrator (when `trustedAuthorities` is set), and backed by valid proof references. +* **Above the trust floor** — every link conveys at least `minLinkTrust`. + +## Attenuation + +Trust degrades along the chain — a longer chain conveys less, all else equal. `effectiveTrust` is computed by `attenuation` mode: + +* `product` (default) — multiply every link's conveyed trust. +* `min` — grade the chain by its weakest link. +* `none` — take the terminal link's conveyed trust. + +`weakestLink` identifies the link that grades the chain. With `enforceMonotonic`, a link that conveys more trust than its predecessor fails as amplification. + +## Questions + +* Who is the root authority of trust? +* Is the chain continuous, or is there a broken link? +* Which narrator is the weakest link? +* How much trust survives transmission to the terminal subject? +* What downstream system relies on the chain proof? diff --git a/examples/isnad-invalid.json b/examples/isnad-invalid.json new file mode 100644 index 0000000..216097a --- /dev/null +++ b/examples/isnad-invalid.json @@ -0,0 +1 @@ +{"input":{"chainId":"isnad-002","rootAuthority":"root:cfo","terminalSubject":"agent:invoice-bot"},"output":{"valid":false,"continuous":false},"expectedResult":"isnad chain broken","explanation":"A gap between narrators breaks continuity (munqati'); the chain is not sound."} diff --git a/examples/isnad-valid.json b/examples/isnad-valid.json new file mode 100644 index 0000000..262f7a3 --- /dev/null +++ b/examples/isnad-valid.json @@ -0,0 +1 @@ +{"input":{"chainId":"isnad-001","rootAuthority":"root:cfo","terminalSubject":"agent:invoice-bot"},"output":{"valid":true,"continuous":true,"effectiveTrust":0.4},"expectedResult":"isnad chain sound","explanation":"Continuous chain rooted at the CFO; trust attenuates to 0.4 at the terminal agent."} diff --git a/src/index.mjs b/src/index.mjs index fb016aa..03809a3 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -1 +1 @@ -export * from './trust_threshold.mjs';export * from './attestation.mjs';export * from './decay.mjs';export * from './delegation.mjs';export * from './trust_route.mjs';export * from './trust_proof.mjs';export * from './transfer.mjs'; +export * from './trust_threshold.mjs';export * from './attestation.mjs';export * from './decay.mjs';export * from './delegation.mjs';export * from './trust_route.mjs';export * from './trust_proof.mjs';export * from './transfer.mjs';export * from './isnad.mjs'; diff --git a/src/isnad.mjs b/src/isnad.mjs new file mode 100644 index 0000000..c9d5651 --- /dev/null +++ b/src/isnad.mjs @@ -0,0 +1,39 @@ +import {failure} from './errors.mjs';import {clamp01,hashObj} from './util.mjs'; +// Isnad-chain trust: verifies a chain of trust transmission ("isnad") from a trusted +// root authority down to a terminal subject. A chain is sound when it is continuous +// (muttasil — every link's issuer is the prior link's subject), rooted at the trusted +// source, every link is individually valid, and trust attenuates along the chain. +const ATTENUATION=['product','min','none']; +export function verify_isnad_chain(i){ + const r=[]; + const links=i.links||[]; + const action=i.requestedAction; + const minLinkTrust=i.minLinkTrust??0; + const trusted=i.trustedAuthorities; + const attenuation=ATTENUATION.includes(i.attenuation)?i.attenuation:'product'; + if(!links.length)r.push(failure('ISNAD_BROKEN_LINK','empty chain')); + if(i.maxLength!=null&&links.length>i.maxLength)r.push(failure('ISNAD_TOO_LONG','chain exceeds max length')); + if(links.length&&i.rootAuthority&&links[0].issuer!==i.rootAuthority)r.push(failure('ISNAD_ROOT_MISMATCH','chain does not originate at root authority')); + let eff=1,minAmt=1,weakest=null,prevAmt=Infinity; + for(let idx=0;idx0&&l.issuer!==links[idx-1].subject)r.push(failure('ISNAD_BROKEN_LINK',`gap between link ${idx-1} and ${idx}`)); + if(new Date(l.expiresAt)!p))r.push(failure('INVALID_INPUT',`link ${idx} invalid proof ref`)); + const amt=l.amount; + if(typeof amt!=='number'||amt<0||amt>1)r.push(failure('TRANSFER_INVALID',`link ${idx} amount invalid`)); + else{if(amtprevAmt)r.push(failure('ISNAD_TRUST_AMPLIFIED',`link ${idx} amplifies trust`)); + prevAmt=amt;eff*=amt;if(amtf.code==='ISNAD_BROKEN_LINK'); + const terminalSubject=links.length?links[links.length-1].subject:undefined; + const envelope={type:'IsnadChainProof',chainId:i.chainId,rootAuthority:i.rootAuthority,terminalSubject,action,length:links.length,continuous,attenuation,effectiveTrust,weakestLink:weakest}; + return {...envelope,chainHash:hashObj({...envelope,links}),valid:r.length===0,failureReasons:r}; +} diff --git a/src/types.mjs b/src/types.mjs index ca31edf..06e03a3 100644 --- a/src/types.mjs +++ b/src/types.mjs @@ -1,4 +1,4 @@ export const PROOF_MODES = ["plain", "signed", "zk-placeholder", "zk"]; export const FAILURE_CODES = [ - "INVALID_INPUT","INVALID_TRUST_SCORE","INVALID_THRESHOLD","INVALID_SUBJECT","INVALID_ISSUER","EXPIRED_ATTESTATION","STALE_ATTESTATION","TRUST_BELOW_THRESHOLD","DELEGATION_EXPIRED","DELEGATION_SCOPE_VIOLATION","ROUTE_INVALID","ROUTE_TOO_LONG","ROUTE_POLICY_VIOLATION","TRANSFER_INVALID","INSUFFICIENT_SENDER_TRUST","PROOF_HASH_MISMATCH","SIGNATURE_INVALID","UNSUPPORTED_PROOF_MODE" + "INVALID_INPUT","INVALID_TRUST_SCORE","INVALID_THRESHOLD","INVALID_SUBJECT","INVALID_ISSUER","EXPIRED_ATTESTATION","STALE_ATTESTATION","TRUST_BELOW_THRESHOLD","DELEGATION_EXPIRED","DELEGATION_SCOPE_VIOLATION","ROUTE_INVALID","ROUTE_TOO_LONG","ROUTE_POLICY_VIOLATION","TRANSFER_INVALID","INSUFFICIENT_SENDER_TRUST","PROOF_HASH_MISMATCH","SIGNATURE_INVALID","UNSUPPORTED_PROOF_MODE","ISNAD_BROKEN_LINK","ISNAD_ROOT_MISMATCH","ISNAD_WEAK_LINK","ISNAD_LINK_EXPIRED","ISNAD_SCOPE_VIOLATION","ISNAD_UNTRUSTED_NARRATOR","ISNAD_TOO_LONG","ISNAD_TRUST_AMPLIFIED" ]; diff --git a/tests/isnad.test.mjs b/tests/isnad.test.mjs new file mode 100644 index 0000000..19cbd62 --- /dev/null +++ b/tests/isnad.test.mjs @@ -0,0 +1,20 @@ +import test from 'node:test';import assert from 'node:assert/strict';import {verify_isnad_chain} from '../src/index.mjs'; +const link=(issuer,subject,amount,extra={})=>({issuer,subject,amount,scope:['invoice.write'],expiresAt:'2026-12-01T00:00:00Z',proofRefs:['p1'],transferable:true,...extra}); +const base={chainId:'isnad-1',rootAuthority:'root:cfo',requestedAction:'invoice.write',currentTime:'2026-06-25T00:00:00Z',minLinkTrust:0.1,maxLength:5, + links:[link('root:cfo','agent:approver',0.8),link('agent:approver','agent:invoice-bot',0.5)]}; + +test('continuous rooted chain is valid',()=>{const o=verify_isnad_chain(base);assert.equal(o.valid,true);assert.equal(o.continuous,true);assert.equal(o.terminalSubject,'agent:invoice-bot');}); +test('product attenuation multiplies link trust',()=>assert.equal(verify_isnad_chain(base).effectiveTrust,0.4)); +test('weakest link is identified',()=>assert.equal(verify_isnad_chain(base).weakestLink.index,1)); +test('min attenuation grades by weakest link',()=>assert.equal(verify_isnad_chain({...base,attenuation:'min'}).effectiveTrust,0.5)); +test('empty chain is broken',()=>{const o=verify_isnad_chain({...base,links:[]});assert.equal(o.valid,false);assert.equal(o.continuous,false);}); +test('root mismatch fails',()=>assert.equal(verify_isnad_chain({...base,rootAuthority:'root:other'}).valid,false)); +test('gap breaks continuity',()=>{const o=verify_isnad_chain({...base,links:[link('root:cfo','agent:approver',0.8),link('agent:rogue','agent:invoice-bot',0.5)]});assert.equal(o.valid,false);assert.equal(o.continuous,false);}); +test('expired link fails',()=>assert.equal(verify_isnad_chain({...base,links:[link('root:cfo','agent:approver',0.8,{expiresAt:'2026-01-01T00:00:00Z'}),base.links[1]]}).valid,false)); +test('out of scope link fails',()=>assert.equal(verify_isnad_chain({...base,requestedAction:'invoice.delete'}).valid,false)); +test('weak link below minimum fails',()=>assert.equal(verify_isnad_chain({...base,minLinkTrust:0.6}).valid,false)); +test('untrusted narrator fails',()=>assert.equal(verify_isnad_chain({...base,trustedAuthorities:['root:cfo']}).valid,false)); +test('non-transferable intermediate breaks chain',()=>assert.equal(verify_isnad_chain({...base,links:[link('root:cfo','agent:approver',0.8,{transferable:false}),base.links[1]]}).valid,false)); +test('chain exceeding max length fails',()=>assert.equal(verify_isnad_chain({...base,maxLength:1}).valid,false)); +test('monotonic enforcement rejects amplification',()=>assert.equal(verify_isnad_chain({...base,enforceMonotonic:true,links:[link('root:cfo','agent:approver',0.4),link('agent:approver','agent:invoice-bot',0.9)]}).valid,false)); +test('chain hash is deterministic',()=>assert.equal(verify_isnad_chain(base).chainHash,verify_isnad_chain(base).chainHash)); From 866a1086c8b8995192ae35963aa080cf46990a21 Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Thu, 25 Jun 2026 20:45:44 -0400 Subject: [PATCH 2/7] Redesign GitHub visual identity for trust-before-execution Transform the repo into a protocol-standard visual experience: dark, precise, cryptographic, enterprise-grade. - README rebuilt as a visual landing page (hero, protocol loop, trust gap, authority flow, decision matrix, decay curve, receipt, architecture, integrations, roadmap, contributor path) - Branded SVG asset system on the TTP token palette, with real brand fonts (Space Grotesk / Inter / JetBrains Mono) subset + embedded as base64 @font-face so they render on GitHub - 1280x640 social preview PNG + trust-ring motif - Reproducible build: assets/brand/embed-fonts.py + render-png.mjs (npm run assets) - GitHub config: PR template, discussion templates, FUNDING, label system + sync - docs/brand/VISUAL_DESIGN.md: tokens, components, badge/label systems, checklist Co-Authored-By: Claude Opus 4.8 --- .github/DISCUSSION_TEMPLATE/ideas.yml | 24 ++ .github/DISCUSSION_TEMPLATE/protocol-rfc.yml | 41 +++ .github/FUNDING.yml | 4 + .github/PULL_REQUEST_TEMPLATE.md | 47 +++ .github/labels.yml | 43 +++ .github/workflows/labels.yml | 21 ++ .gitignore | 3 + README.md | 358 ++++++------------- assets/brand/README.md | 33 ++ assets/brand/embed-fonts.py | 87 +++++ assets/brand/fonts/Inter-Regular.ttf | Bin 0 -> 66592 bytes assets/brand/fonts/Inter-SemiBold.ttf | Bin 0 -> 66800 bytes assets/brand/fonts/JetBrainsMono-Medium.ttf | Bin 0 -> 57404 bytes assets/brand/fonts/JetBrainsMono-Regular.ttf | Bin 0 -> 57404 bytes assets/brand/fonts/SpaceGrotesk-Bold.ttf | Bin 0 -> 31916 bytes assets/brand/fonts/SpaceGrotesk-Medium.ttf | Bin 0 -> 32016 bytes assets/brand/fonts/SpaceGrotesk-SemiBold.ttf | Bin 0 -> 31960 bytes assets/brand/render-png.mjs | 24 ++ assets/brand/trust-ring.svg | 26 ++ assets/diagrams/architecture-stack.svg | 48 +++ assets/diagrams/contributor-path.svg | 23 ++ assets/diagrams/decision-matrix.svg | 60 ++++ assets/diagrams/execution-receipt.svg | 41 +++ assets/diagrams/integrations.svg | 20 ++ assets/diagrams/protocol-loop.svg | 29 ++ assets/diagrams/roadmap.svg | 50 +++ assets/diagrams/runtime-authority-flow.svg | 70 ++++ assets/diagrams/trust-decay-curve.svg | 53 +++ assets/diagrams/trust-gap.svg | 49 +++ assets/social-preview.png | Bin 0 -> 131109 bytes assets/social-preview.svg | 87 +++++ assets/ttp-hero.svg | 88 ++++- docs/brand/VISUAL_DESIGN.md | 132 +++++++ package-lock.json | 264 ++++++++++++++ package.json | 11 +- 35 files changed, 1483 insertions(+), 253 deletions(-) create mode 100644 .github/DISCUSSION_TEMPLATE/ideas.yml create mode 100644 .github/DISCUSSION_TEMPLATE/protocol-rfc.yml create mode 100644 .github/FUNDING.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/labels.yml create mode 100644 .github/workflows/labels.yml create mode 100644 assets/brand/README.md create mode 100644 assets/brand/embed-fonts.py create mode 100644 assets/brand/fonts/Inter-Regular.ttf create mode 100644 assets/brand/fonts/Inter-SemiBold.ttf create mode 100644 assets/brand/fonts/JetBrainsMono-Medium.ttf create mode 100644 assets/brand/fonts/JetBrainsMono-Regular.ttf create mode 100644 assets/brand/fonts/SpaceGrotesk-Bold.ttf create mode 100644 assets/brand/fonts/SpaceGrotesk-Medium.ttf create mode 100644 assets/brand/fonts/SpaceGrotesk-SemiBold.ttf create mode 100644 assets/brand/render-png.mjs create mode 100644 assets/brand/trust-ring.svg create mode 100644 assets/diagrams/architecture-stack.svg create mode 100644 assets/diagrams/contributor-path.svg create mode 100644 assets/diagrams/decision-matrix.svg create mode 100644 assets/diagrams/execution-receipt.svg create mode 100644 assets/diagrams/integrations.svg create mode 100644 assets/diagrams/protocol-loop.svg create mode 100644 assets/diagrams/roadmap.svg create mode 100644 assets/diagrams/runtime-authority-flow.svg create mode 100644 assets/diagrams/trust-decay-curve.svg create mode 100644 assets/diagrams/trust-gap.svg create mode 100644 assets/social-preview.png create mode 100644 assets/social-preview.svg create mode 100644 docs/brand/VISUAL_DESIGN.md diff --git a/.github/DISCUSSION_TEMPLATE/ideas.yml b/.github/DISCUSSION_TEMPLATE/ideas.yml new file mode 100644 index 0000000..c0bb375 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/ideas.yml @@ -0,0 +1,24 @@ +title: "[Idea] " +labels: ["type: docs"] +body: + - type: markdown + attributes: + value: | + ## Idea / Integration + Share an integration surface, use case, or improvement. Not every idea + needs an RFC — start the conversation here. + - type: textarea + id: idea + attributes: + label: What's the idea? + validations: + required: true + - type: input + id: surface + attributes: + label: Enforcement surface (if applicable) + placeholder: "e.g. agent tool call, CI/CD stage, API gateway, service account" + - type: textarea + id: value + attributes: + label: Who benefits and why? diff --git a/.github/DISCUSSION_TEMPLATE/protocol-rfc.yml b/.github/DISCUSSION_TEMPLATE/protocol-rfc.yml new file mode 100644 index 0000000..8ce3877 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/protocol-rfc.yml @@ -0,0 +1,41 @@ +title: "[RFC] " +labels: ["type: protocol", "status: needs-rfc"] +body: + - type: markdown + attributes: + value: | + ## Protocol RFC Discussion + Use this to socialize a protocol change before opening a formal RFC in `rfcs/`. + Keep it focused on the **trust-before-execution** boundary. + - type: textarea + id: motivation + attributes: + label: Motivation + description: What trust, authority, decay, proof, or receipt gap does this address? + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposal + description: The concrete change to grammar, semantics, schema, or the trust model. + validations: + required: true + - type: dropdown + id: layer + attributes: + label: Protocol layer + options: + - Language / grammar + - Trust scoring & decay + - Delegation & isnad chains + - Authority grants + - Proofs + - Execution receipts + validations: + required: true + - type: textarea + id: compat + attributes: + label: Compatibility & security impact + description: Backward compatibility, failure modes, and any fail-closed considerations. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..59032b5 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# Trust Transfer Protocol — funding & sponsorship +# TTP is an open protocol stewarded by BlockSiFr. +github: [BlockSiFr] +custom: ["https://blocksifr.com"] diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..16112a7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,47 @@ + + +## Summary + + + +## Protocol Layer Impact + + + +- [ ] Changes protocol grammar / `.ttp` language +- [ ] Changes a public schema (AuthorityGrant / Attestation / ExecutionReceipt / …) +- [ ] Changes trust scoring, decay, delegation, or proof semantics +- [ ] No protocol-surface change + +## Runtime Enforcement Impact + + + +## Receipt / Evidence Impact + + + +## Tests + + + +```text +``` + +## Screenshots or Diagrams + + + +## Checklist + +- [ ] `npm test` passes +- [ ] Docs / examples updated (if behavior changed) +- [ ] An RFC is linked for any protocol-surface change +- [ ] No `cleartext-dev` assumptions introduced into production paths +- [ ] Commits are signed off and scoped diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 0000000..a548f27 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,43 @@ +# Trust Transfer Protocol — canonical label system. +# Synced to the repo by .github/workflows/labels.yml (EndBug/label-sync). +# Colors follow the TTP brand token palette. + +- name: "type: protocol" + color: "00D4FF" + description: "Protocol grammar, semantics, or schema" +- name: "type: runtime" + color: "0066CC" + description: "Runtime authority gate and enforcement" +- name: "type: docs" + color: "8892A0" + description: "Documentation and concepts" +- name: "type: examples" + color: "00B8A9" + description: "Example .ttp files and integrations" +- name: "type: security" + color: "FF3D00" + description: "Security-relevant change or concern" + +- name: "status: good first issue" + color: "00E676" + description: "Approachable, well-scoped first contribution" +- name: "status: needs-rfc" + color: "FFB300" + description: "Requires a protocol RFC before implementation" + +- name: "priority: critical" + color: "FF3D00" + description: "Blocks correctness, security, or release" + +- name: "area: trust-decay" + color: "00D4FF" + description: "Trust scoring and decay model" +- name: "area: execution-receipts" + color: "00B8A9" + description: "Execution receipts and evidence chain" +- name: "area: zkp" + color: "0066CC" + description: "Zero-knowledge proofs" +- name: "area: compiler" + color: "8892A0" + description: ".ttp parser, evaluator, and CLI" diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml new file mode 100644 index 0000000..f73f7a3 --- /dev/null +++ b/.github/workflows/labels.yml @@ -0,0 +1,21 @@ +name: Sync labels + +# Applies the canonical label system in .github/labels.yml to the repository. +on: + push: + branches: [main] + paths: [".github/labels.yml"] + workflow_dispatch: + +permissions: + issues: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: EndBug/label-sync@v2 + with: + config-file: .github/labels.yml + delete-other-labels: false diff --git a/.gitignore b/.gitignore index d509f43..594dda0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,8 @@ dist/ **/dist/ .runtime-authority-receipts.json .cortextrace/ +__pycache__/ +*.pyc +.venv/ *.log .DS_Store diff --git a/README.md b/README.md index a66c04a..cbe8890 100644 --- a/README.md +++ b/README.md @@ -1,319 +1,175 @@ -

Trust Transfer Protocol

-

- Trustworthiness establishment for autonomous systems. + Trust Transfer Protocol — Trust-Before-Execution for AI agents and non-human identities

- TTP is the open protocol for proving whether an AI agent, copilot, workflow, pipeline, API, service account, or non-human identity is trustworthy enough to be relied on before downstream authority and execution decisions occur. + spec + protocol + runtime + reference +
+ trust model + receipts + category + license

- No implicit trust. No stale delegation. No blind reliance on autonomous actors. + The protocol layer for agent trust.
+ Every action must earn authority before execution. Every decision must be provable after.

- Protocol - Category - Runtime - Production - License - Security policy + Read the Spec  ·  + Quickstart  ·  + Examples  ·  + Contribute

-Identity proves who is acting. Authorization says what was assigned. TTP establishes whether the actor is trustworthy enough for this context, right now. +--- -TTP is a platform-agnostic trust protocol for evidence-backed trustworthiness establishment across autonomous systems. +Identity proves *who* is acting. Authorization defines *what* was assigned. **TTP establishes whether the actor is trustworthy enough for this action, right now** — before any downstream authority or execution decision is made. -OAuth standardized delegated access. -SCIM standardized identity provisioning. -TTP standardizes trustworthiness establishment before autonomous execution. +OAuth standardized delegated access. SCIM standardized identity provisioning. **TTP standardizes trust-before-execution for autonomous systems.** It is a platform-agnostic trust protocol — bring any agent, IdP, gateway, or workflow. -## Status +

+ Identity, Attestation, Trust Evaluation, Runtime Authority Gate, Decision, Execution Receipt +

-* Protocol draft. -* Reference evaluator active. -* MVP parser and trust decay evaluator available. -* Not recommended for production enforcement by itself. -* TTP establishes trustworthiness context; it does not enforce execution alone. +## Why TTP Exists -## First Principles +Software is moving from advising to acting. Agents call tools, copilots trigger workflows, pipelines modify production, service accounts move data. The old model — `authenticate → authorize → execute → log` — never asks the question that matters at runtime: -Software is moving from advising to acting. +> **Should this specific action execute right now, given how trustworthy the actor is at this moment?** -When software acts, it must be trustworthy. -When trust is stale, reliance becomes risk. -When trust decays, trustworthiness must be re-established. -When trustworthiness is evaluated, evidence must be produced. -When downstream authority systems act on that evaluation, a receipt should exist. +

+ Identity asks who, Authorization asks what may be accessed, TTP asks whether this action should execute now +

-The old model is incomplete: +## How TTP Works -```text -authenticate -> authorize -> execute -> log -``` +Trust is established from evidence, scored against a threshold, and checked at a runtime authority gate **before** the action runs. The gate consumes a trust proof, an authority grant, and the current decay state — then emits a decision and a signed receipt. -Autonomous systems require a new model: +

+ A request is evaluated by the runtime authority gate against trust, authority and decay, producing a decision and a receipt +

-```text -identity -> trustworthiness -> authority -> execution -> receipt -``` +### Runtime Decisions -TTP defines the protocol layer for establishing trustworthiness before downstream authority and execution decisions. +A trust proof resolves into one of five outcomes. TTP establishes the trust context; downstream runtime authority systems enforce the decision. -## The Category +

+ Decision outcomes: allow, throttle, step-up, escalate, deny +

-Autonomous systems have crossed from recommendation into execution. +## First Example -AI agents call tools. -Copilots trigger workflows. -CI/CD pipelines modify production. -Service accounts move data. -APIs execute financial and operational decisions. -MSPs and MSSPs act across customer environments. +Declare a subject, attach evidence, and require a trust threshold before the action is allowed: -Existing systems authenticate actors, assign permissions, and log activity. They do not define a portable protocol for establishing whether an autonomous actor is trustworthy enough to be relied on in a specific context. +```ttp +trust "invoice_agent" { + subject = agent:invoice-bot + issuer = trust-issuer:finance-control + score = 0.91 + decay = exponential(halflife = 6h) # trust weakens without fresh evidence + scope = [invoice.read, invoice.write] + evidence = [attestation:att-7b3c, receipt:rcpt-01J9F4] +} -TTP defines that missing layer. +policy "write_invoices" { + action = invoice.write + require_trust = 0.80 # threshold the proof must clear + on_below = step-up # otherwise demand fresh attestation + execution_policy = gate # decide before execution, fail closed + emit = execution_receipt # cryptographic proof of the decision +} +``` -OAuth standardized delegated access. -SCIM standardized identity provisioning. -TTP standardizes trustworthiness establishment before autonomous execution. +Trust does not stay still. Without fresh attestation it **decays** through `active → degraded → warning → critical`; a new attestation **recharges** it. -## Stack Alignment +

+ Trust decays over time across active, degraded, warning and critical bands and is recharged by attestation +

-TTP establishes trustworthiness. -SCIM-RE structures runtime trust context. -RAP evaluates authority. -Execution Exchange enforces downstream decisions. -CortexTrace records evidence and receipts. +## Execution Receipts -```text -TTP -> SCIM-RE -> RAP -> Execution Exchange -> Protected Systems - | - v -CortexTrace - | - v -ExecutionReceipts -``` +Every decision produces a signed, hash-chained `ExecutionReceipt` — evidence, not a log line. It records what was decided, the trust state behind it, and the cryptographic basis to verify it later. -TTP does not govern execution directly. -TTP establishes trustworthiness. -Downstream runtime authority systems decide and enforce what happens next. +

+ Execution receipt with subject, action, resource, decision, trust score, references, signature and chain hash +

-## Add Trustworthiness to Your Agents +## Architecture -Your agents already know how to act. -TTP helps prove whether they are trustworthy enough to be relied on. +TTP is the foundation layer. Runtime governance, the authority gate, and the enterprise control plane build on it; agent frameworks, CI/CD, APIs, and copilots consume it. -Bring your existing agents. -No agent rewrite required. -No IdP replacement required. -No workflow migration required. +

+ TTP architecture stack: protocol, SCIM-RE governance, runtime authority gate, execution exchange, consumers +

-Add an evidence-backed trustworthiness layer around your agents, tools, APIs, workflows, and non-human identities. +> TTP establishes trustworthiness. **SCIM-RE** structures runtime context, **RAP** evaluates authority, **Execution Exchange** enforces decisions, and **CortexTrace** records evidence. TTP does not enforce execution by itself — see [COMMERCIAL_BOUNDARY.md](COMMERCIAL_BOUNDARY.md). -```text -Agent identity -> trust evidence -> TTP trust proof -> authority evaluation -> downstream decision -> receipt -``` +## Integrations -| Step | What you do | What TTP provides | -| --- | --- | --- | -| 1. Register the actor | Define the agent, service account, API client, pipeline, or workflow as a Subject | Establishes who or what is being evaluated | -| 2. Attach evidence | Add trust claims, attestations, issuer context, freshness rules, and decay behavior | Establishes whether trust is current and evidence-backed | -| 3. Generate a trust proof | Evaluate the trust context before downstream authority decisions | Produces proof that RAP, Execution Exchange, API gateways, or CI gates can use | +Bring your existing agents — no rewrite, no IdP replacement. TTP wraps the boundary where an action happens. -Register the subject. -Attach evidence. -Evaluate trust. -Produce proof. +

+ Integration surfaces: GitHub Actions, CI/CD, API gateways, service accounts, Microsoft Copilot, Azure DevOps, LangChain, CrewAI +

-Keep your agents, copilots, APIs, IdPs, and workflows. -Add an evidence-backed trustworthiness layer before downstream authority and enforcement. +## Roadmap -## Developer Quickstart +

+ Roadmap phases from spec and reference through production hardening +

+ +## Quickstart ```bash git clone https://github.com/BlockSiFr/ttp-protocol.git cd ttp-protocol npm install npm test -npm run ttp -- check examples/01-basic-agent.ttp -npm run ttp -- eval examples/02-trust-decay.ttp --subject agent:invoice_reviewer --at now -``` -Expected check output: - -```json -{ - "ok": true, - "file": "examples/01-basic-agent.ttp", - "subjects": 1, - "trust_claims": 1, - "proofs": 1, - "authority_contexts": 1, - "delegations": 0 -} -``` - -Expected eval output shape: - -```json -{ - "subject": "agent:invoice_reviewer", - "effective_score": 0, - "required_score": 0.7, - "result": "TRUST_PROOF_EXPIRED", - "reason": "trust claim expired before evaluation", - "proof_mode": "cleartext-dev", - "evaluated_at": "2026-06-25T18:27:15.881Z", - "expires_at": "2026-05-11T20:00:00.000Z", - "receipt_hash_optional": null -} -``` - -First trust proof path: - -```bash +# evaluate the reference examples +npm run ttp -- check examples/01-basic-agent.ttp +npm run ttp -- eval examples/02-trust-decay.ttp --subject agent:invoice_reviewer --at now npm run demo ``` -The demo prints reference decisions, trust scores, and ExecutionReceipt identifiers for local non-production scenarios. +`check` validates a `.ttp` file; `eval` evaluates a subject's trust at a point in time; `demo` prints reference decisions, trust scores, and `ExecutionReceipt` identifiers for local, non-production scenarios. ## Protocol Primitives | Primitive | Meaning | | --- | --- | -| Subject | The human, agent, service account, pipeline, API client, workload, or workflow whose trustworthiness is being evaluated. | -| TrustClaim | A scoped statement that a Subject has a trust score or trust state issued by a specific trust issuer. | -| TrustIssuer | The entity responsible for issuing or attesting to a TrustClaim. | -| AuthorityGrant | A bounded right or delegated authority context that may only be relied on when trust, freshness, scope, and constraints are satisfied. | -| Attestation | Fresh evidence that the subject, credential, workload, code, runtime, or operating context remains valid. | -| TrustDecay | The time-based weakening of trust when fresh evidence or attestations are absent. | -| Delegation | The bounded transfer of trust or authority context from one subject, issuer, or workflow to another. | -| TrustProof | A structured proof that trust conditions were evaluated and satisfied or not satisfied. | -| RuntimeDecision | A downstream enforceable decision derived from trustworthiness, authority, evidence, and context. | -| ExecutionReceipt | A signed proof object recording the evaluated subject, action, resource, decision, trust state, authority basis, evidence references, timestamp, and receipt chain context. | - -## What TTP Establishes - -| Actor | Trustworthiness question | TTP role | -| --- | --- | --- | -| AI agent | Is this agent trustworthy enough for this tool, data, or workflow context? | Evaluates trust claims, attestations, scope, and decay | -| Copilot | Is this delegated action backed by current trust evidence? | Binds trust proof to the requested action context | -| CI/CD pipeline | Is this workload trustworthy enough to promote, deploy, or alter infrastructure? | Evaluates trust before downstream CI/CD gates act | -| API client | Is this client trustworthy enough for this sensitive endpoint? | Supplies trust context to gateway or service decisioning | -| Service account | Is this non-human identity still trustworthy for its assigned task? | Detects stale, decayed, or unverified trust | -| MSP/MSSP operator | Is this customer-impacting action backed by current trust and evidence? | Produces trust proof for delegated operational action | - -## Trust Proof Outcomes - -TTP produces trust context and trust proof results. - -| Trust proof outcome | Meaning | -| --- | --- | -| trust_valid | Current trust evidence satisfies the proof requirement | -| trust_insufficient | Effective trust is below the required threshold | -| trust_expired | Trust claim or proof freshness has expired | -| trust_invalid | Syntax, issuer, evidence, reference, or proof validation failed | -| trust_unknown | Trustworthiness cannot be established from available evidence | - -## Downstream Runtime Decisions - -Runtime authority systems may convert trust proof results into enforceable decisions. - -| Runtime decision | Meaning | -| --- | --- | -| allow | Execution may proceed | -| throttle | Execution may proceed under rate, volume, or scope limits | -| step_up | Fresh attestation or additional approval is required | -| escalate | Human or higher-authority review is required | -| deny | Execution is blocked | - -TTP itself establishes trustworthiness. -RAP, Execution Exchange, API gateways, CI gates, and integrated runtime systems enforce downstream decisions. - -## Integration Paths - -| Integration path | Best for | How it works | -| --- | --- | --- | -| Agent trust wrapper | LangChain, CrewAI, MCP tools, custom agents, OpenAI tools, Claude tools | Wrap the agent or tool boundary with a trust proof | -| API trust check | Sensitive APIs, SaaS actions, service-to-service calls | Supply trust context before the gateway or service relies on the actor | -| CI/CD trust proof | GitHub Actions, Azure DevOps, GitLab, Terraform, deployment workflows | Establish trustworthiness before merge, deploy, promote, or infrastructure change | -| MSP/MSSP trust proof | ServiceNow, Jira, ConnectWise, Sentinel, Defender, remediation, decommissioning | Prove customer-impacting work is backed by current trust evidence | - -First trust proof in minutes. -Production enforcement with Execution Exchange when ready. - -## Why It Matters - -| Buyer | Value | -| --- | --- | -| CISO | Establish whether autonomous actors are trustworthy before downstream authority systems rely on them | -| CTO | Deploy agents and automation without losing confidence in who or what can be trusted | -| Compliance | Convert trust evaluations and downstream decisions into evidence | -| Platform engineering | Add trust proof checks to APIs, CI/CD, agent tools, and workflows | -| MSP/MSSP | Prove customer-impacting actions were backed by current trust evidence | -| Identity team | Extend identity context into dynamic trustworthiness | -| Security engineering | Detect stale, decayed, or unverified trust before sensitive reliance | +| **Subject** | The agent, service account, pipeline, API client, workload, or workflow being evaluated. | +| **TrustClaim** | A scoped statement that a Subject holds a trust score or state, issued by a trust issuer. | +| **AuthorityGrant** | A bounded right relied on only when trust, freshness, scope, and constraints are satisfied. | +| **Attestation** | Fresh evidence that the subject, credential, workload, or runtime context remains valid. | +| **TrustDecay** | The time-based weakening of trust when fresh evidence is absent. | +| **Delegation** | Bounded transfer of trust or authority from one subject to another. | +| **IsnadChain** | A verifiable chain of trust transmission from a rooted authority to the acting subject. | +| **TrustProof** | A structured proof that trust conditions were evaluated and satisfied — or not. | +| **RuntimeDecision** | A downstream enforceable decision: `allow`, `throttle`, `step-up`, `escalate`, `deny`. | +| **ExecutionReceipt** | A signed proof object recording the decision, trust state, authority basis, and receipt chain. | ## Open Protocol, Commercial Enforcement -Open source TTP includes protocol grammar, trustworthiness semantics, the trust proof model, public schemas, example `.ttp` files, SDK primitives, a reference evaluator, non-production demo gates, public ExecutionReceipt schemas, public AuthorityGrant schemas, public Attestation schemas, the TrustDecay model, documentation, RFCs, and example integrations. - -Commercial BlockSiFr capabilities include Execution Exchange runtime enforcement, managed Runtime Authority Gate, production RAP service, tenant governance infrastructure, HSM-backed signing, production ExecutionReceipt ledger, CortexTrace enterprise evidence engine, CAIF / IFC optimization engine, enterprise adapters, compliance evidence packs, customer policy templates, behavioral scoring weights, risk-cost-compliance scoring model, managed service control plane, enterprise trust graph, enterprise evidence exports, production policy orchestration, and customer-specific baselines. - -TTP establishes trustworthiness. -Execution Exchange enforces downstream runtime decisions in production. -CortexTrace records and verifies execution evidence and receipts. - -See [COMMERCIAL_BOUNDARY.md](COMMERCIAL_BOUNDARY.md) for the explicit boundary. - -## Security Posture +Open-source TTP includes the protocol grammar, trustworthiness semantics, the trust-proof model, public schemas, example `.ttp` files, SDK primitives, a reference evaluator, and the TrustDecay model. Production enforcement — managed Runtime Authority Gate, the Execution Exchange control plane, HSM-backed signing, and the CortexTrace evidence engine — is commercial BlockSiFr infrastructure. The boundary is explicit in [COMMERCIAL_BOUNDARY.md](COMMERCIAL_BOUNDARY.md). -TTP is currently a protocol draft and reference implementation. +## Security -Do not use cleartext-dev proof mode in production. +TTP is a protocol draft and reference implementation. **Do not use `cleartext-dev` proof mode in production.** Production trust establishment and enforcement require a trusted issuer registry, signed claims, replay protection, clock integrity, key rotation, tenant isolation, fail-closed enforcement, receipt signing, and audit retention. See [SECURITY.md](SECURITY.md) and [THREAT_MODEL.md](THREAT_MODEL.md). -Production trustworthiness establishment and downstream enforcement require: +## Contributing -* trusted issuer registry -* signed claims -* replay protection -* clock integrity -* key rotation -* tenant isolation -* fail-closed downstream enforcement -* receipt signing -* audit retention -* policy review -* evidence integrity -* attestation freshness -* secure key management -* protected commercial control plane +From a first issue to owning a protocol surface — the path is open and intentional. Start with [CONTRIBUTING.md](CONTRIBUTING.md) and [GOVERNANCE.md](GOVERNANCE.md). -BlockSiFr Execution Exchange provides commercial production enforcement capabilities. - -## Repository Map - -| Path | Purpose | -| --- | --- | -| [examples/](examples/) | `.ttp` examples and non-production trust proof demos | -| [src/](src/) | MVP parser, evaluator, and CLI | -| [spec/](spec/) and [specs/](specs/) | Protocol notes, schemas, and reference contracts | -| [docs/concepts/](docs/concepts/) | Concept documentation for trustworthiness establishment | -| [docs/integrations/](docs/integrations/) | Integration notes for agents, CI/CD, gateways, and MSP/MSSP workflows | -| [docs/enterprise/](docs/enterprise/) | Enterprise security model, threat model, deployment, and commercial boundary notes | -| [rfcs/](rfcs/) | Protocol RFC structure | - -## Build the Trustworthiness Layer - -TTP is open protocol infrastructure. +

+ Contributor path: start here, good first issue, protocol RFC, runtime implementation, docs and examples, maintainer path +

-Use it to model trust. -Use it to evaluate evidence. -Use it to establish trustworthiness. -Use it to produce proof. +## License -Use Execution Exchange when trust proof must drive production runtime enforcement. +[Apache-2.0](LICENSE) · A [BlockSiFr](https://blocksifr.com) open protocol · Trust-Before-Execution for autonomous systems. diff --git a/assets/brand/README.md b/assets/brand/README.md new file mode 100644 index 0000000..876d1bf --- /dev/null +++ b/assets/brand/README.md @@ -0,0 +1,33 @@ +# TTP brand assets + +Self-contained SVGs with the real brand fonts (Space Grotesk, Inter, JetBrains +Mono) subset and embedded as base64 `@font-face`, so they render identically on +GitHub — where external font loading is blocked. + +## Files + +- `fonts/*.ttf` — brand font faces (decompressed from `@fontsource`), used by the + build. Committed for reproducibility. +- `embed-fonts.py` — subsets each font to the glyphs a given SVG uses and embeds + them. Idempotent; safe to re-run. Requires `fonttools` + `brotli`. +- `render-png.mjs` — renders an SVG to PNG with the brand fonts (`@resvg/resvg-js`). +- `trust-ring.svg` / `repo-icon.svg` — decorative marks (no embedded text). + +## Authoring + +1. Write the SVG with brand `font-family` names and a `/*@FONTS@*/` marker as the + first thing inside `", "", svg, flags=re.S) # ignore CSS, count only rendered text + text = " ".join(re.findall(r">([^<]*)<", body)) + chars = set(text) | SAFETY + chars.discard("\n"); chars.discard("\t") + return chars + +def subset_b64(path, chars): + opts = Options() + opts.flavor = "woff2" + opts.desubroutinize = True + opts.notdef_outline = True + opts.hinting = False + opts.glyph_names = False + opts.layout_features = ["kern", "liga", "calt"] + font = TTFont(path) + sub = Subsetter(options=opts) + sub.populate(text="".join(sorted(chars))) + sub.subset(font) + font.flavor = "woff2" # Options.flavor is not applied on save; set it on the font + buf = io.BytesIO(); font.save(buf) + return base64.b64encode(buf.getvalue()).decode("ascii") + +def build_block(svg, chars): + weights = {int(w) for w in re.findall(r"font-weight:(\d+)", svg)} or {400} + weights.add(400) # default for faces declared without an explicit weight + rules = [] + for fam, wght, fname in FACES: + if fam not in svg or wght not in weights: + continue + b64 = subset_b64(os.path.join(FONT_DIR, fname), chars) + rules.append( + "@font-face{font-family:'%s';font-style:normal;font-weight:%d;" + "src:url(data:font/woff2;base64,%s) format('woff2');}" % (fam, wght, b64) + ) + return BEGIN + "".join(rules) + END + +def process(path): + with open(path, "r", encoding="utf-8") as f: + svg = f.read() + if MARKER not in svg: + return False + svg = re.sub(re.escape(BEGIN) + ".*?" + re.escape(END), "", svg, flags=re.S) + block = build_block(svg, used_chars(svg)) + svg = svg.replace(MARKER, MARKER + block, 1) + with open(path, "w", encoding="utf-8") as f: + f.write(svg) + return True + +def main(argv): + targets = argv or glob.glob(os.path.join(HERE, "..", "**", "*.svg"), recursive=True) + n = 0 + for t in targets: + if process(t): + print("embedded fonts:", os.path.relpath(t)); n += 1 + print("done:", n, "file(s)") + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/assets/brand/fonts/Inter-Regular.ttf b/assets/brand/fonts/Inter-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f297b9c321f3b7df60a641bd7e32c3290bdc814c GIT binary patch literal 66592 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

qbmK8{&0V&KgjRz_hJ5^ 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 literal 0 HcmV?d00001 diff --git a/assets/brand/fonts/JetBrainsMono-Regular.ttf b/assets/brand/fonts/JetBrainsMono-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ffc3e87cf8b78623f78e61fccab4fa97494184dc GIT binary patch literal 57404 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 literal 0 HcmV?d00001 diff --git a/assets/brand/fonts/SpaceGrotesk-Bold.ttf b/assets/brand/fonts/SpaceGrotesk-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ecf7cd39fc2020c67a32cea8c38c1058a6c77c11 GIT binary patch literal 31916 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 literal 0 HcmV?d00001 diff --git a/assets/brand/fonts/SpaceGrotesk-Medium.ttf b/assets/brand/fonts/SpaceGrotesk-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..161396a137a230d486cc08065e001fcdd641b833 GIT binary patch literal 32016 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 W)RtH#ZG`PIIT1&^z$;<}_WuD?Y8xg1 literal 0 HcmV?d00001 diff --git a/assets/brand/fonts/SpaceGrotesk-SemiBold.ttf b/assets/brand/fonts/SpaceGrotesk-SemiBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2ae635c7a2475d16c00d07a8631cce4fa794f151 GIT binary patch literal 31960 zcmdtL34ByV);C;rJLyh3Nhh78)7jHYI-Py%B%OWV6G9SJ0YR380NF^wj*1Ji2)Ln+ zf{M6~GmoRbI^&Eu`lydOKCa`gjDzc_gN!I5GSc_`pSrh`4j}qIzxVro-|y?2b8p?c zwVXQV)TvWd=iV^R7z@M6kFlouhDQ6gxTB19-^mzHZR(slEm}HW$=I|P8B4Y_O`B1> zbI+AC8C!E08D5?`Ehj(HZu$$-Zbc~ZPA{*G~9oV`gimXEnaxzE%zKlQSYGq=7EK4hj}i$2haPE-ZHpwpr>T%{1c3| zqF!m=@X+X3-j>-B8+4gY$Ie&pJVC zs%he=`vOz-Gplv4ZIYv3A$=QEo$h-(sS z(9m@+U_YMERj+Gty?{BSb`~Su#%iSHEK;+PS)@x@v^2m1rD~QV)vz?_V%8!}VR^Xb zNewKIKf>Zfcqwb){;Y`WNP*0E#07(88{O^&H@@Y;(d8Ud{TjHWEp%a!Sz|d3*-DD9-Ri7 z2E-AMe1UjGyd)l-1vG0APkifB_(r_*0{55y4c?XG`W)b|<2)n2od%i@5w}_JwL$QU zc<2j|4}J%;^M{#@9|E7wXA#niz&C*9OBs;C^}wSaK(e+GyzXZjX(pau!osB=SiGi` z88yX#jVub!dQ@0)TG)Hvg!n?h63CU6CxcG}F999`JPNoOKygiwvD+X=0Q8~^(Avlc zSS%kzJ?I-E4zfX4FOaN^hp&T7sn1ZKm9J%q1PG@}_W(|^IL#*$K=tqyC?9|{MZhnD zfbx!)^Bmg!93y=w>I4sp04>yq2)yyq5M&v2XXxvEHOd5_oJ`RMv;*Nf_Be}R(45{p z&>4ArDhnaNb0=Q|egF`jXcJ@^{jf@708RdgvOx<$kA9XuUJlU+fPAF@E8m22092-^ zO=wxBK{yg;F0Ou3Bd*g~HSeQg8XK)n>iMdYvuYW|Bb%lxktQtd!NT zxojcZ!1h6JKF?ldhuG)rYn0k8J*Jilg{cWpOO3EZTjE8j`IeH?OO?MvxdDvH7**uQ z5oYqe@~?5eN4^*5XDP-bo%-g~R}^CG)PWC!KQtejLg7O-hw^bwKD6>s@!xm+edph& zeDLcJo)`4!#^XW2TEHfD1GvMsI6EQ2j2-g{GxiPc=%<|3Bf&i;e_H~TO4pU`fvgHu1U->^mOCH5NoHT#zRfjtUIna76N zI`DD>+sG~iM-Q-z*(K~!b{V^zZAJ_Cv8&jx*iGzawukLyw?H;;Ww*2a><)G(yNlh! z?gkxhL+jsSU$a+v3_Ho*N9#M-RMw3VwTn$-r+6S^k8*kQ1AaTH(L?I74Lm-^qj@&3 zd@uhqf0utQ`AhLqqqIWWFa1>$ugTJMXclTVX>QRxqaLYyIQ;7xi!IKhhu8e;4EzWDJT4as-tH%?er^ zG!%4k(4L@2gFL|v!E=I#f;R+j3BE3PZ}6kR&xGWK421k4Vw!7u(DbC~71IZ% zZ%lGjbX0xRtf&=H7e(C^_1ma}QU5fX%}HjbImhfaSDD+*)6MhDyUY)mA2&a1e#QKb z`4jU|^AFKU(RtBz(QVNyqi>A9JNiKMU!#x4l*ZJ>w8d0ai?=F6999GV;!%95aSr^0fyr4$+qid@$GD3dW#Yj;@lix81wx7xIbh;rjO z9^+}G)`^hYT~t(v$9QV8OUCE>XP>1Mgw3@s} z1OKznhWQG2HVE`0#d6T zM1=X>)xo`44`wo^q<5rwZKAUiN3C#(3^R z%7%3$EWp_YKDiK&`5X0^LNG*dhGfNLN5|p%6&J28F3fkW3;2Zt z1D?wUM!lHyp$yCiscgt6=XQ-9l^Boh@w~#zZaWFt^nA<{Jok8R;dam8yt%Z<<*($j znt*vTuzGMneX2>t(@^mg5>Kr|p;YXLTaDWejTyH-zm-J(dTGU}da38s9s-rKvyfA8 zmhvGd<@)Tdur;6FHIZY*sp}z6B&UPmSqNE=f&wbjpcT}9K^h@4ig#VQXV0aV-F)+9 z9kXV2Oqn%Hkx?P2{c}6+@0cr2WHpg&RRaS>Mvdcr&Tcmv$GcbqkE>l$TGms&|AvC9 z%EB9@0|g6e4AmDDcuw-s;yis`F?dxVca3A0a&G)0RPMQ4rZZ4opItH*UvYMXJ>Qn( zHWnnFui{M-6$J~7Bwf`NIuq#((Q_v^AftAXyE4<6wKgvC*}DtMN(=9n4rEU&4XWt~ z50moK|M6B#lII(~!JQqL1Jjf<2WVXmS{HcxhgaANQc|4GY-vL4Qe~pYL`FrK&Cpa( z!@Q_-L*tt1jZMwAn(V}eo}%)>*4DAQHMYw1%IbuYjKt>tikel1lKzg^*oOMj>?CJ& zkTxu@qpE67ZvK)st2Lt_IyW=k855`r%j>MJx}b<~iUF@k{&m!1MdrVJO^SU@nmRCW z>Oo3T1FX+SiU<{J$dlSd5CB?Jr?0D7+tJ)IWo`9(L&aDp|BI)f5gnPo=y7+BRiFgY z-XxJ!hlaGbOY`!dHr{HuZR2B*-)p2H(Gx*)4b?*uucQ(wN#-wExTf8>=(R=0wzZ31 zTWnl{TsKO~1k_8bPF;yQqEW|kDb0J__ z&t0C|c(CUfazd*~i;^#LSATv zhTzbgIlRYn7k}HchcCOC-)rc<*)!YFkEAROl*`~hvJ}j4n3*&p4XZ9?2+%nzB^rHA zk&swB2`}`a=yEg!M@D^AFg-7Cru(W~SH3G?d2r$E>V-q`>0Qa$Mr~q+wWN8gBRkjN zXmsV*+Y_C6IS#wC+PQGvQ;7?blO#iG!u%Sy-jbB)AUs-tM+fkZV#$JsPCGOk^nyS@ z84geD>jRB#M&rs+W012dr=qvAa_Ria?yjoJY10gOi8WAV$0BV}Wh0$oog-ySy4v*Z zot^Fawl0#EJk*tfHe=rD9Rq|VVb*0!XqZqXq+s1ivAVjk=BA#?z#+dxcWPRV z!%>q~Q57&0T-jqNAL%r7j+E!mDl#Xz677x92@T0r`LP8vUDPV7smP~QV!To65<0KY zu036aMU?lUEfv|-&LHE+ura(f+1o6&F;TWi9(=04CNa;qSxQ~eXjKephDq%*nXFOX z_Gnz9)AEegl~t9)EzSMqo}E%hNpX>3fuV5r^QZjk3f;Aas?jOI9V1m$BkgIWjd@9V zaTOW7EU&bbs0SU)Z$g{GAz|o^5EaM^q{C#w*?8OKmzU&hniIcuE5B;NlDv`yiCqgk zD-~K4OGUshf#%z8Rgaj-u}mN~z32 z9QRWR^Id4iP+5LL&8dg;N|q#EWwb|^4K++{(l>W>H0zsSW^&BCm}D1xP)0vhsxVxs zrcTSKF(A1tt7LZGXjxH3BgE&Z(H7;JSLJz!CzY3VwVlMg7s`meEIloyu|gR<{-UI22asAF z`CCSzJ!s?y-kJ#hJwq3PyqH|V;x#K5n9N@ECju=ijUg4TqFT&5s>`z5vPQGhvIEGw5B zx!yjN91e|}=%Xg6KPmF6Xe1*vA5}mGBXwXQxO`Go{2Az?>g)>C)mPrw8g3l+$ll7h zHayv@jdGJ}PPI;|Orbts&c9}c3F=d)!ZZji2r5V}ugtIHM@o|7dkfv3k4VBY8y6esueVp^G}ZnlcTwlNPu|+DTf# zih)5W0thIXqh#Iq=ayV@$>^?K@rz6HxMRU>w=M7-NnC(@4e|*oksncQS!DE%)MDxb zb;z|PvvWt#37eq(LK*^G=U2i!{;<5Xv+blOyde$?J<4cpKq)?>_3!tuUvJ#7em_6r z>E$Bu-E|wMwskkRc1|&Dzw-XAJ9loq|H|!sv%CJ#J#%*FAEwPDYLh}+ z4ebPKV@{;A!(Qi-aoL9J-;nw~Wufv6)SCusQ5SK$Dg*jicHF;+j;+&o%Sw4l5)t1yaR($%`4A~G^0xiHzUsH(2U7}~zP*uAJ$UpKET zBEn!vOVVLuO0iZ8fEo0oGU9oyRbiXj3*CZTI@9<%0nhDNS3fqbzP{aF=D6Z3&$ax> zp|t$Dr7%j1m$ih4Ry5bS0+TaMmu?R2+j~){v$Hy=eu*1&g}h6PP?Mgd38PgZOi-MZfR&}Z!58+#Rgo>-}US<2H8teD|^Z-#|)**8})%Dt?iY870uys2EKXufzY^! z!rs=Pmi}_D6jXv6RZ# zq$D>Wub9{5X9r~E=Vt|ELpMn*16UVKqP(;boRVR1U)pjJ;7$y_FsjpOJ247??OARP*Y%C8*Ewh65 zEpiC&l#XINCfi=Dwb7`8wKXW|U#AxprQdU5T-=4<7Nu*F(~A}*o{CRgL_9MhpIOa^ z6(?jAD^JQQopEDa+{U{z3JWv7U6d$&lDMcS{l|mpVy5OmzCR+LU2w~r&9`2y-A=tx z!GMRS7g_uJtpbg7yTM>j7s&7u+n|k?5JsNQY}sMiHqU23Ou_3erF^r37tK{bRBu&k z!J>&;J1|X84hcz42fpb=w*G!wQ95wuv7$^KOQ?IELtUQd6#NT-|0PPhMX$l)WRc56 zqcB*=FX`VsWyhLM;|%R-u-(+pG^ z9vB$z-`(E6``bkqZ|2cgT(qcd?|RP%>uzZSz2#$aG2ekc0{c(LT|AhljCkIAUUT`6 z8;KhYvYtJvNuj5(d5jIC$Nl2}{Rzq1#1rV|2t3n>=cA*1kU#2aKDC$5DF54u^8Hah zkMX=W%2PxIuxs6X5Bo%VLDFFlgGp&h41WYN>{Mc)`Deh!Ri98=^yV2nUMhbQ7VtUp z=OEQ#N_BerpDJA*VV|(uB`wuUCCek&Ldt$=>0}2y^7;J5q9&?W)eOWZ4}#xz54mqHff| ze}uI^UDS;;pQGR;;++)F=U^T%LsD@426VXtxKet0dQ{2BVXlE!0%yTvXhJvmr1Qai z#;Q^k_k;Y9$MWTP11MiH)d%h)AMsx!*278Y3yLUTetrt_KF{CxIHYIt&}sszF&Uc3 z44jg&S0`p%>iW5==Oi=9mI!OmzLCLg}v)l)=h3)AJkoXSAN;a1=URCY{M_;@5cY;OA?P9@YQ$ z^51S)5!SyR(o>I=_b4gdFejXaE`O7M{n4XZe!k}p{rdi}6&sM6^BGlLUL(m)qD3n`lLjkgrXGbgs~R%F5^apWANU z{@jYb0~b{ftw~ApGdZGaha18ghifA(;gy~njG>iv6^nPacic1_w({nVK5p-V)zKwR zXqg3KUyD9wBirAl(#l=vUDXm3Dv~m+I*7T7lLil3$@*8t`GuAuOI~%+`DH85&#lH{ z&We%w^FJIK%B`-;nqHPsldca5ZLKPwp0U8?vS&ptSg^qJ@`BgV1q(pwEau@~qTU>6 z;X;?$?R2`$IHMMw+3hy#aK^an)S1mXC(c-?bvt!BryJ+2sm=an#knPEA=s}BNh`@K zDf4fhN|6Y9BXf%p$scP74o)wja8qYzlgO1Gtmc}C6uBTrk)TD7W)1Y0pU^``*)E|| zmH5@;@o!>Rm-N@dhkd^%-L4g2@Wk)wm#8UeyR>$6CkBBm8M<77sjYs=yCsI>O zl`;-CA{J#c_JSxG>pN8P>y)+xoz72`pv1lzLTR5xY=uwkyEjwp3y3YzP`OIlgSS!% zgu^TiQ5zN;+7Y{wV#WT4s10KnFg}V=W+I+2R^s1e*t8i>?~O-GmQTb|*_0Y(k4?l9 z9wL?<98_ZOk_I(F-dG-n;TLmD@X-n>52D%7BtDYDz>rFo5;~KMZ<*kxr}y@U9=d(3 zw|7is=N&iK?%Cfvys%^8FmM$s_o8iB9T#o8U9>@or#2|@Z^BD~Fq<5Yw)IWKQY$F6 zmL2S;SZH@?v7kKWAcE6R;X1MRW1^h}H|$77dC}ggy7OxH$2j|EWz%QBvIXS%bluLu z;#}%#5r8b-~|Ei;2DiH?oZ$LZ5spZbbd6%+`2XIgn-VYz5$9(p_0>CsLL+NWc0v+HryU}f&8 zRHV_Ooles8{#tce&Rv9MIjjLk78BoEy%rDm)n zz1ktx9#f01aT|E`81@Nw*M;BdQ*W+l+^Kb3$ZuM`O#vf06o@`-S z-H#T0w*fEkeHC#>i6y>MEb;yKg71^#!S|Yp)Wl(>jQ86SEB_lg{~}6OR+_(lmC|Br z&jTeYS&4nsNNJxV{o)h*&R&ZBD`H&|m8+zE|86P)>&aLLCn*EnpaWurjwj5pih|fo zf$`Vy5TevdJk_VfzY4#kGvm<`!dXpCWm9UDJ!>MC@DQ==eKqzm)R^s!lWi{-ab+c^Tc_^{)t1~-^gknsjVGpZe9{^Ok7;qyrSH*3)>uSw_!nO z!OYr*-dJP&lG@5H@V%>xPZir9_1?AT;=H_K+WIJIQno%ybMlIP7NXzGD=o*E-vX-j z!@5>6b-IQ1N()a;r!Y9iomDV>#7ezbHWo%3`Km;YZ<*d*IV(S4X`m}JHOrI|la`)p zv&5#kGi(i6BXz5%R9sM$lpn9x$Hk}DIdf+l((95f&a4buRH7*`G%PR4o*8A#v074W zQ|ml!{K4}ss!eap$*9N(_Yc;E>4QSktMc;NGl>&o=9YJ>s-weAH*>)A?1>f1!V2jgofYF;I=G zJHeFk{Y@v7p3nB?o$l5)Y+%`~c5PcwTWxJugta0zNecEer$;z5XGJGj`1E3TVX-m6 zZjFjbEv>8HYO0Hl(#J+Nq@)H#N0>0YNbuO4&aXrLLF5gi)~|RpK?^I3agkB)P3!5I zHm$dJT2^6UR%THVpT2PR>U6vG^t zb7rnuSX8{Yil;B`x;Q>Qzr2!L3(hMGDxZ@NpOX2f_VbJXUY4iLD~ARtkdH~f!ptTD zBVe7c2ALSyCtRr%W5uo7F0{>kR?nyN=Uma!a>bnRxtm*BHqQ+UUASV!!q7#_m-p99 znNrhOKieD^6Bi#H6EnLmxM|D6)eE;Ysh8RP%hxXN7pInv*2S$;JE}rW=7fZp%VOf= zV)_zO{YIW$oH07Oh|O1b)he zTi28Hq_HlkPFevjW1HRWbSwH61H9+!f?WQ@a|TG*wl?lV&+QX|@df zpZL=BYVQ1T9!4%`W2pf$hkYt=K=49c4;$|Q#1ZTnMRL}45yu@9e^YxyitIj`v_x$;wT>)s9E-it!R(z?()fsj(&-Bg^lqzT* ztH<_HV^5`i$Um_t&Fi5NI22OZvv%pZd^CEccTS~(BH{9JX-ImOT4Hu`b7!TLRH@IG zZq0}1TfF?O^f&1*ct*S0SqzGp(rA42#ulhFM1&Mew-%pT(%qzM>K3Q=G)t&8HPsqwN#j$x8+Fay-Oakj?sgF)p3(Sh zl#grD(T)_3mVknfz+*$lzQX$;-luV=Kjm@!zs1uiQD4_={t2${ZLZLKDPm*=QUeSj?D+C-Zyis z6l2ZdE9p#kkg*>27I6FwMSXqu0%5}UQs7%kX=shmgmphDz%!5E z>3NYCTzdVk>xX*6dM2lH7b0PyziA0CK%zS@r4&QgW7&o3WN1s0=p&OTNOh}J^!&j0 z-?pP~2mWqTXx7Bx>eOHBQxR?9EOmvkl@Im&gzvBnc_Co5F8Qw-SnAZrkIF`u;9Ro z=`%y4Vj?0#g9AkiexC+}59FtTrmDT;DaJwCjn z*V9?885ylv*>r~IpED^jHI?s7YtGJYPEDnA+Ih~Tq!foG$w|_hfj5@OqZgK{kk1S$ z4flV-J>D@C&(rvRasQ5bpUAI}9-x`W`12jo6J&P^3C@s;`H-~RE14O*UMik9Pbn!L zC4YpRpfi;$XYx3#T4^!kB>e{2gMNDwDV+IS1gf^Z`y=Xy*o)-ycZ)t&FY=2E-W&-3B&sONjP=@N9;^UY1n&v0zDI0!ulH5DX>Y$!@Ndt zF+KgCDmSIHG@Cs&)ovTVDrJ4k_h`2LOj%Pc85txIKX}Xf_RO+qPq3Ho(>RFA%AR29 zi09dxHBbClqfjG@JuN+rnkLOD)+A+RC8203E6qlz+0uwAat?c1rWuHsGkA5TH|=X_ ziX6gB-M>`o00PKfN9 zVskoe1QxqJ$&#ELT$&wkjnIVn+mmUslx+78(L`9|vr8Mzk>mv(X}%@O7#+L}WmOYc!d{Kkl08Gf z*KWA3X5I7)uUK2(lvihKnbKah_7YDvpXzy#Pc>Y-WAAyJ8n&%6h1E^VY|p*Fectq1 zW7OF86JAS)v@rGU8wYS7#-^cJF9(W7P?-uN978n;g|7+ z)W26b`|@V8n)c<6P}!&rD<{gxl0dR|mf93I2jL^@+w_S6W~}z7T6@+Oau$m|+KutR za=K2&@~?2NSKUl$0`+KPw|16aNadY|uNB6WzAX;MzQ`DbX4e6K4!~ zrLiqABDNrNvu_RC`-sKhlQOQkMvNcdV`N(+Mm9XTx@Sv+^!=tysI35RcwZ*=fiW0O z>=|3fcaNnD;Z5t%KJkR-Ej1AMz=aQB8+pY>@0HqKk8-XXFK2v5**YHLeNQ~0J13kRT_~*+yJT)}br>v|L@QGIXPV3YD7EgAi|Ysqj<;B>kBGo1S!VGRXu<6+{6DZ z^?XD=p#$_*UIgA^{taJ7mItk~c`c6xs&0NA)-Q|{D=c6_DT)0G-ae;UH0@qJo;04A zY&OMWKj)h2wHf8*8JT63X<f!^&c? zWhQ(p`Gjxfo%$&5@0l+pc#aqp=gQw2mhbSC2m85sGX&W$0RKzz-cR*I=ewgq{9&`WY8;?0g)t@jXn}-!>BV)%s8m!GzWo4lvE=m zvJ#z!?9{vXE1DqcLA1iMb_$<0Wp0wDDM>tgjDLb}o2bwFYxvrlhIFYV9p$K=H}D!; z0GZ~jiWl(h_}&B3((Jy9xAB5$(}+K0bA2Sd)?ss<#c$mO_MhFAeP}3t@qyfu#f#5y zYM~e{3{6HNmV0b9^B>`^p~CXC#^CC*fOxCL z91~NO9@5ZS6e8v3CA*V||7Xt7(m}ye@L$WyFgd4DL74-iZftj+V1|!xfQcGgY#;`zRcu+!GadfmXR38>jLPx!Y@6xQJwT5%o zu(aG_OpS|9G6tCpp%DQQ<(4qI4cF6cp!8LCmN_7$%Fz-)y(vtSyMZ`wK^l2zmry49~u-N9TgLA(^ghj z7Znv5^ih$Gpx&7?UM!ADB|`p6NhF0u(I!1bb03#canNxo4m(C!ne%ijGa!CUneiwy zAWtwP%O)R3@9aZwhK$j?XR=OLm+-Ol{AAm-X>IM@-EGuu>?tYw?#3Eg7B?sgl}8*fRbZKTLYZNkdG)hiu+W-Enk{1MO~C)6}~ug+`_Hg#_c?rJMi6_`*;d>@>KRVPs3hk2G8VK_<~Fh&&79w^5KkLzzca1ck^Oi z!b^D>FXt7!l2`F+SVy(Ij@R=B-pHGHGjHLo7|Pq>3){h`VvOj5MKR5<17Bp2>be6L zE?za(vv_D=k#5!CvfSL-67`y|UR^;VzNR48m78Z6Po2GZ;b@OYl3!aVuJB}1uDSWa zl*N^s@0+MreORnMEFOQDpPyH#K6D2!85&#E(?7I^FbZ5aGBUJg$1AB*7ji}Ekq&%Y#o-G|&xLQ!jFdh>4hx82%tys8dNO>4O=}sgFT$YW`1oltw zZd2%3R6}$W&CPdt309!eq+pyTU__yIVA&veBhu#9 zACw@~6`%xx#^|!O;-Lr#G$>}QS7EQKSiLIk&aJ5r866uLTG2DGYzgr@U~Ivd;2I^% z&&@5-kM)i8C~a1QqB zCDDmE1y@vF3+2l(tCpd~@Ro}B-k||ee$a*i(39=ZrKLD>5vIM+0O+Y#*r)6>d?W00 z_63hb9KN%N@3~3Pn_4LC4-hhl&@<|@jq3F#^?ET<#2{Ay?)A{C9C|kz=U5!{Mwks} z()t`VX5yR!Jx^ZwZ3&#f0W7Fk&+?`dL7kNYudD-!%00>HE^vIKQN!cWqyiuE+UfSlyf*ljak{{zo_~&@*_#l6azsg_W&)^GSkK${8l;yYlZoUuKoB3`$+r_u?OZi5u z*)cxM_lfk&@pK8SP9$HiZ6+IW5B|f--T9!t?nUYxIy*55Cj( z4Mw@o*ddHhZ=kwEkc#K=U9|%U{~quF^4y0jXP5IMIA2O<{**Z1hZz#*m>}V-p&02( z8M1*nBBjX|@p%-cwMCrY!Z#K<$7BR&e-VGVh<{t8cZqnH2;VQlpfOUmh?oo!P8H!g z5yrbWc$zC>u(O76j0jsqn7&HDIjx%EEW-2!AkI_7Ia{1TCB)>2aF+;^Hx1|Xy$sI( zAY#C8V19{+af_JU6vlVqDE?9r-z?(s{T}4%6yd2Nj8z20q=|5q2-9jU=VA|!w~H{= z>Jd{;Vc2MXkU$+|L@(^75XfyPWZQ_I?zOLC(aXtZvcSr)iM~Ez-FYp$0@2q8(Z|0> zU&Ry*){OF{z7bseQByCj7Xan}rUN;(nZe@{daV|An*V|3Vo*RfI~D zpL+ar@$w1Z6kZCAU;pX*^i0Z=jQ$UQN&mxqld@sA;S4UxUn+Qd`@%1i7Wq5zHQMpg zC(8BqXhoV)Hssv*_seJ?dW~0Wh=rbsGUT7Qm*1X9qlA80U8m;~Z<3r5`O72l&DKxk zhtcx?5dHi22%*QyU&#;1|0zoG_RHJlTj*ZiEk7wg^7G}Bra0qAa*^p1yB+HQ=l*s7 z)MH4;7XTm4DZi$qmH!SbcL06`*pD|d(HeR}TI<|D8CJ~C|1eGn`957%&YjbnTK-Jo zv;5^ag#sw&cwZf-i2T4$mngq=wrBDYCH4%NBac9z-?#<<-+$@PJ1YEKk2`a``=vGf zKb>xz!afy^Q%oHt<&!=Se=>+sT~Jg$jYmj-lG18ecYRU{3>J| znnnJQqJDl9Rx)~fi~KkFU-BX3J0u^Zv+~sE9Ib@q7pWekc*^J5&jjUt^2b7x+(+Mp z7WTsP(7)fv56TBb)=H%S`62pBG*ax7|MZLW$)w)k?aN+iBZ-%9_m(WmJw~mSPk2)( z&nC{}+TtDgZ9xTZ-;up(;8Bp#tIaOvG zh#$9s6?%Bb0xxys54@rOZ(QZC<&V5$kBTvDdi134+2{?wjh&vVUpJ1g9oKO5X8N>x8!~`DzM{j{}*Q<)W><4c-UY!Zs?JvHRQZ2d@mLy=1|~^XxaCeVSO!fS14t8WmkR-=_lEbXRm|CRrIFM zMQP)fgBbUZgGT=nxsuhg-}X}JObI`G=_vb*h8^J9*ehOuea=R)=iP#x)Xmr%-h%&v z(SvU?+=Ep|+VQv;>&kCnFZC@PmtvLqJ?x5ph~sjx!>}3u3*3_X6#YNp>6Rv!mys2fai%g{4r-t!k)85?4;O15k1yeld+2F zz!4~R(}To*dZ5@*4?r2T&ys~B0PB_62$P>h0Cs(Hfl(d~J@#Pov9saAVGw&Uv7l=q zaungvfWB_vQjEibefSd8LAyrjpl}&@P>v%Rdm5FfwF-xmRpX%VP}BgUIvh4|p#kT1 z?9hjUPBYL-;!TX;jS0LN1hwdYjYwjzI~2R!n-IPP9Pk6jHiH6NuvYAkJ!<-{;%vMxJ^4K0eBXOgJ`P< z=g7xED;fR?f9TCdgwl0$d=;pgl7ao{)U#g?z*c`JkP(81RVXBSFYV zfshY_kPoveA696dK+xX~-jGZL2$|4@69w<%!21F4 zjQ0Hegakyv^I;eiSP9PuKOqev@O)SYDy>I9<&cX_h$qRAgk%^X89TrMk_nxViBMH0 zUWN?l(7Rtjd#QiNoFNBR$ib(e2km$2u;ckTQhtF$CuBk=q(LX-z#$~SCL|zENPr1@ zBJ|}I#y047>n_!;#mg~$y7{_xTx$X4x_n)o5U!DYc@YA*|e<) zAq{x30i5##?RB7A2;@2Z3_qKA$YhexRdz@sdHQ(0e3YFa^6)8!^i)G)Y9S}&+0%@* zJg*QWC8S~}^u<;1$GL`G z3%x-SLOR3uKP24>y|E7(;}OWpYvMmIy}>?$Opru;0pFY>kc1Q1HrBug#sKb{u}5h^ z%OCN)OJ~`D)~8_p-~^-rnlbBX6FvA5IYOie5ofzN7oj(QC`Ym{4`Cz_|Z1uCD+-1$+kh2jFwS7XU5%p~x3%A^e?M z;9*n*kEB-YJkJGJ{4l35;~lUVSfjD>DZF{|-*~h6Rh9s|qz})Q0hR++0Qvy~fI+}! zq><`B^5)cK8 z!Yu!eMWZz_SPP1kKLREX;oY$xm<2O#E5HV@%g^8ohDT9;BffQglw|{Qkv9+V`6$N) zE2#kG79l(YSP$3$*a)}~a1r2Qz$U;YsOwU|Wq`{8n^E5u)VCF|4X_Z#=qDp6@y#Sk5EW9O>78T?Anc_?AMz~&EC;Lr^aBO}gMck4 zV=G`AU_0PSzz)Dpz)!VqH_E>ra04XhM!>mR`v&kmj$l+R_pBJ@mO#!*VOy7D zHdl%JYCsL336$!?bs1neUo-7QQ+w4;1n0Ey{fa zcSn(qylR@zV<^X5a0Wgvn3FW4|4`^8LLVW8M&y19H5gG(Gtz4j_c21h6LHt0oEu;* z?1Pq~R>^omEp7r|>HY`YKa5d?@(|{2^4nZ1r{Y;NzLeJnyNOEun@CG|eknpfBIFUd zjv?1^obcSP1At`elIS zfE9p#zyM$nuvz|&ha(LJeQ5E$+@|^mtylen@Wv6G(k!gDqrKk3GT|&|Aw1AtTI~hJ zfGzn=1S0q3SnXM3{e5C}s8uOJ$xl`Xm7yCiS&0u?ym(-kU8J1J(U7g}9a*@T4U!un z>mw&Vwn&`kiStbI8DpKpxUkkSI@hB_@r`|)BSbh@oVDT%%n?tul7$MFBGvnY?n7`d ziMS|@1-8i%d~56m9GBv)p zhx9Mbkv|wYqfv@=JSS)E;0V!)-Wb#a1AJQqP%i3bB8<@=zP(@Jzi&$LZNhjD&)FoA zGF_x5EScy>dRQT_KE^E%uiXKgL!=R2TBvORcjzDEaT4m&!#5W5-cH`C;&%Ixb^c|V7_36v&Xk%0R? z_;kmLxl4&iM}C8}>!sAG;8u?Gkz$6gaF7enNJ>K%x`H)Pg(xwB1M!oraZ0Di68#@p N [width] +import { Resvg } from "@resvg/resvg-js"; +import { readFileSync, writeFileSync, readdirSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const FONT_DIR = join(HERE, "fonts"); +const fontFiles = readdirSync(FONT_DIR).filter(f => f.endsWith(".ttf")).map(f => join(FONT_DIR, f)); + +const [, , inPath, outPath, width] = process.argv; +if (!inPath || !outPath) { + console.error("usage: node render-png.mjs [width]"); + process.exit(1); +} +const svg = readFileSync(inPath, "utf8"); +const resvg = new Resvg(svg, { + fitTo: width ? { mode: "width", value: Number(width) } : { mode: "original" }, + font: { fontFiles, loadSystemFonts: false, defaultFontFamily: "Inter" }, + background: "#0A0A0F", +}); +writeFileSync(outPath, resvg.render().asPng()); +console.log("rendered", outPath); diff --git a/assets/brand/trust-ring.svg b/assets/brand/trust-ring.svg new file mode 100644 index 0000000..6364dad --- /dev/null +++ b/assets/brand/trust-ring.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/diagrams/architecture-stack.svg b/assets/diagrams/architecture-stack.svg new file mode 100644 index 0000000..8c54914 --- /dev/null +++ b/assets/diagrams/architecture-stack.svg @@ -0,0 +1,48 @@ + + + + + + + + + + L4 + Consumers + Agent frameworks · CI/CD · APIs · Copilots + + + + + L3 + Execution Exchange + Enterprise control plane · evidence & receipts + + + + + L2 + Runtime Authority Gate + Decides allow · step-up · deny before execution + + + + + L1 + SCIM-RE · Runtime Governance + Authority grants · policy · runtime execution context + + + + + + L0 + Trust Transfer Protocol + Trust scoring · decay · delegation · proofs · receipts + FOUNDATION + + diff --git a/assets/diagrams/contributor-path.svg b/assets/diagrams/contributor-path.svg new file mode 100644 index 0000000..7f78ce4 --- /dev/null +++ b/assets/diagrams/contributor-path.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + 01Start HereREADME & concepts + 02Good First Issuesmall, scoped tasks + 03Protocol RFCpropose a change + 04Runtime Implbuild enforcement + 05Docs + Examplesteach the next dev + 06Maintainer Pathown a surface + diff --git a/assets/diagrams/decision-matrix.svg b/assets/diagrams/decision-matrix.svg new file mode 100644 index 0000000..7563983 --- /dev/null +++ b/assets/diagrams/decision-matrix.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + allow + Trust clears threshold. + Action executes. + PROCEED + + + + + + + throttle + Marginal trust. + Rate-limit the actor. + SLOW + + + + + + + step-up + Fresh attestation + required to continue. + RE-PROVE + + + + + + + escalate + Route to a human + authority for review. + REVIEW + + + + + + + deny + Trust below floor. + Action is blocked. + BLOCK + + diff --git a/assets/diagrams/execution-receipt.svg b/assets/diagrams/execution-receipt.svg new file mode 100644 index 0000000..ee651dc --- /dev/null +++ b/assets/diagrams/execution-receipt.svg @@ -0,0 +1,41 @@ + + + + + + + + + + EXECUTION RECEIPT + + + + VERIFIED + + receipt:rcpt_01J9F4…A2 + + + + + subject agent:invoice-bot + action invoice.write + resource erp://invoices/2026-06 + decision allow + trustScoreAtDecision0.87 + authorityGrantRef grant:9f2a…c41 + attestationRef att:7b3c…e90 + timestamp 2026-06-25T18:40:12Z + + + + + signature ed25519:5d1e…b7f4 + chainHash sha256:c0ffee…a17b + diff --git a/assets/diagrams/integrations.svg b/assets/diagrams/integrations.svg new file mode 100644 index 0000000..4a868c3 --- /dev/null +++ b/assets/diagrams/integrations.svg @@ -0,0 +1,20 @@ + + + + + + + GitHub Actionsenforces at: workflow jobREFERENCE + CI/CD Pipelinesenforces at: pipeline stageREFERENCE + API Gatewaysenforces at: gateway requestEXPERIMENTAL + Service Accountsenforces at: token issuanceEXPERIMENTAL + + Microsoft Copilotenforces at: tool callPLANNED + Azure DevOpsenforces at: release stagePLANNED + LangChainenforces at: agent toolEXPERIMENTAL + CrewAIenforces at: agent stepPLANNED + diff --git a/assets/diagrams/protocol-loop.svg b/assets/diagrams/protocol-loop.svg new file mode 100644 index 0000000..8dc2b6d --- /dev/null +++ b/assets/diagrams/protocol-loop.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + 01Identitynon-human actorasserts itself + 02Attestationsigned evidenceis presented + 03Trust Evalscore vs.threshold + 04Authority Gatechecked beforeexecution + 05Decisionallow · step-up· deny + 06Receiptsigned proofis emitted + + + diff --git a/assets/diagrams/roadmap.svg b/assets/diagrams/roadmap.svg new file mode 100644 index 0000000..7dc2367 --- /dev/null +++ b/assets/diagrams/roadmap.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + PHASE 1 + Spec & Reference + SHIPPED + + + + + PHASE 2 + Runtime Authority + IN PROGRESS + + + + + PHASE 3 + Proofs & Receipts + NEXT + + + + + PHASE 4 + Integrations + PLANNED + + + + + PHASE 5 + Production Hardening + PLANNED + + diff --git a/assets/diagrams/runtime-authority-flow.svg b/assets/diagrams/runtime-authority-flow.svg new file mode 100644 index 0000000..870fbc6 --- /dev/null +++ b/assets/diagrams/runtime-authority-flow.svg @@ -0,0 +1,70 @@ + + + + + + + + + + REQUEST + agent:invoice-bot + invoice.write + + + + + + + + + + Runtime Authority Gate + evaluates before execution + + trust proof + authority grant + decay state + + + + + + + + + + + + allowexecute + + + + step-upre-prove + + + + denyblock + + + + + + + + + + + + RECEIPT + decision: allow + sha256:9f2a…c41 + signed · immutable + + diff --git a/assets/diagrams/trust-decay-curve.svg b/assets/diagrams/trust-decay-curve.svg new file mode 100644 index 0000000..f097009 --- /dev/null +++ b/assets/diagrams/trust-decay-curve.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + 1.0 + 0.0 + time + + + + ACTIVE 0.85–1.00 + DEGRADED 0.65–0.85 + WARNING 0.40–0.65 + CRITICAL 0.00–0.40 + + + + + + + + + + + + + + + attestation + + diff --git a/assets/diagrams/trust-gap.svg b/assets/diagrams/trust-gap.svg new file mode 100644 index 0000000..a20a5e0 --- /dev/null +++ b/assets/diagrams/trust-gap.svg @@ -0,0 +1,49 @@ + + + + + + + + + ESTABLISHED · IDENTITY + + Who is acting? + Authentication proves the actor + is who it claims to be. + + + OAuth · OIDC · SPIFFE + + + + + ESTABLISHED · AUTHORIZATION + + What may it access? + Static grants define scope — + assigned once, rarely revisited. + + + RBAC · SCIM · IAM + + + + + + THE GAP · TTP + + Should this action + execute right now? + Live, evidence-backed trust + gates the action before it runs. + + + TRUST · DECAY · RECEIPTS + + diff --git a/assets/social-preview.png b/assets/social-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..8c101bde1036d772ecc2a13c2f62da2d033d2087 GIT binary patch literal 131109 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 z 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 literal 0 HcmV?d00001 diff --git a/assets/social-preview.svg b/assets/social-preview.svg new file mode 100644 index 0000000..0dd8242 --- /dev/null +++ b/assets/social-preview.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BlockSiFr + / + TTP + + + + PROTOCOL v1.0 + + + + OPEN SOURCE · AGENT TRUST INFRASTRUCTURE + Trust Transfer + Protocol + Trust-Before-Execution for AI Agents. + + + + + + + + + + Identity + + + + + + Trust + + + + + + Authority + + + + + + Execution + + + + + + Receipt + + + + diff --git a/assets/ttp-hero.svg b/assets/ttp-hero.svg index bfe0d89..9463ce2 100644 --- a/assets/ttp-hero.svg +++ b/assets/ttp-hero.svg @@ -1 +1,87 @@ -ActorsHuman Agent API CITrust Evidenceclaims attestationsTTP Trust ProofestablishDownstream AuthorityRAP gateReceiptevidence chain + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OPEN SOURCE · AGENT TRUST INFRASTRUCTURE + + + PROTOCOL v1.0 + + + Trust Transfer + Protocol + Trust-Before-Execution for AI agents & non-human identities. + + + + $ npm install @blocksifr/ttp-protocol + + + + + + + + + Identitywho is acting + + + + + Trustis it trustworthy right now + + + + + Authorityis this action permitted + + + + + Executiongated runtime action + + + + + Receiptcryptographic proof of the decision + + + + + + + Authority Before Execution·Trust Decay·ZK Proofs·Execution Receipts + diff --git a/docs/brand/VISUAL_DESIGN.md b/docs/brand/VISUAL_DESIGN.md new file mode 100644 index 0000000..19ed1db --- /dev/null +++ b/docs/brand/VISUAL_DESIGN.md @@ -0,0 +1,132 @@ +# TTP Visual Design System + +The visual identity for the Trust Transfer Protocol. The repo should read as the +reference implementation for the **Trust-Before-Execution** category: dark, +precise, architectural, cryptographic, calm, enterprise-grade. Engineered, not +decorated. + +> Metaphor: a runtime execution gate where **authority, trust, proof, and +> receipts** converge. Cyan is a precision signal, never a background fill. + +--- + +## 1. Color tokens + +| Token | Hex | Role | +| --- | --- | --- | +| Trust Black | `#0A0A0F` | Primary background | +| Cipher Dark | `#12141C` / `#101521` | Panels & cards | +| Border | `#1E2430` | Thin technical borders (1px) | +| Gridline | `#FFFFFF` @ 3% | Subtle structure | +| Signal Cyan | `#00D4FF` | Primary accent — verified trust, precision only | +| Deep Azure | `#0066CC` | Secondary accent — authorization | +| Near White | `#F0F2F5` | Primary text on dark | +| Steel Gray | `#8892A0` | Metadata, borders, subdued copy | +| Proof Green | `#00E676` | Verified / allow | +| Quantum Teal | `#00B8A9` | Protocol support / throttle | +| Drift Amber | `#FFB300` | Warning / step-up / escalate | +| Breach Red | `#FF3D00` | Deny / critical | + +Functional colors map **only** to decision states: `allow` (green), +`throttle` (teal), `step-up` (amber), `escalate` (amber + flag), `deny` (red). + +## 2. Typography tokens + +| Use | Family | Weights | +| --- | --- | --- | +| Display / hero / headings | **Space Grotesk** | 600, 700 | +| Body / interface | **Inter** | 400, 600 | +| Code, API paths, policy, receipts, hashes, CLI | **JetBrains Mono** | 400, 500 | + +GitHub Markdown cannot load custom fonts, so branded fonts live in **SVG +assets** with the real font files subset and embedded as base64 `@font-face` +(see [§7](#7-asset-build-pipeline)). Plain Markdown stays clean and accessible. + +## 3. Visual principles + +- Dark mode first · high contrast · generous whitespace +- Thin 1px borders (`#1E2430`); gridlines at 3–5% opacity +- Circular **trust-ring** motif; node-and-edge diagrams; small monospaced labels +- Sparse cyan highlights; no heavy gradients, glow, cyberpunk, robots, padlocks, + or stock illustration +- Every element communicates **authority, execution, verification, or proof** + +## 4. Badge system + +Grouped, intentional, dark-labelled (`labelColor=0A0A0F`, `style=flat-square`): + +- **Protocol status** — `spec v1.0` (cyan), `protocol TTP` (teal), `runtime in-progress` (amber), `reference Node.js` (green) +- **Security model** — `trust-model decay-enabled` (cyan), `receipts cryptographic` (teal) +- **Community** — `category agent-trust-infrastructure` (steel), `license Apache-2.0` (azure) + +## 5. Label system + +Canonical labels live in [`.github/labels.yml`](../../.github/labels.yml) and are +synced by [`.github/workflows/labels.yml`](../../.github/workflows/labels.yml). +`type:` (protocol/runtime/docs/examples/security), `status:` +(good-first-issue/needs-rfc), `priority:` (critical), and `area:` +(trust-decay/execution-receipts/zkp/compiler) — each colored from the palette. + +## 6. Component inventory + +| Component | Asset | Purpose | +| --- | --- | --- | +| Hero | `assets/ttp-hero.svg` | Above-the-fold identity + protocol flow | +| Social preview | `assets/social-preview.png` | 1280×640 share card | +| Trust ring | `assets/brand/trust-ring.svg` | Circular motif / watermark | +| Protocol loop | `assets/diagrams/protocol-loop.svg` | Identity → … → Receipt | +| Trust gap | `assets/diagrams/trust-gap.svg` | Identity vs Authorization vs TTP | +| Decision matrix | `assets/diagrams/decision-matrix.svg` | Five outcome pills | +| Authority gate | `assets/diagrams/runtime-authority-flow.svg` | Request in → decision out | +| Trust decay curve | `assets/diagrams/trust-decay-curve.svg` | Decay + attestation recharge | +| Execution receipt | `assets/diagrams/execution-receipt.svg` | Cryptographic proof card | +| Architecture stack | `assets/diagrams/architecture-stack.svg` | L0–L4 layers | +| Integration tiles | `assets/diagrams/integrations.svg` | Surfaces + status | +| Contributor path | `assets/diagrams/contributor-path.svg` | First issue → maintainer | +| Roadmap strip | `assets/diagrams/roadmap.svg` | Phase timeline | + +## 7. Asset build pipeline + +Sources are authored with brand `font-family` names and a `/*@FONTS@*/` marker. +The build subsets the real fonts to each file's glyphs and embeds them. + +```bash +npm run assets:fonts # embed brand fonts into every marked SVG (idempotent) +npm run assets:social # render assets/social-preview.png from its SVG +``` + +Fonts (`assets/brand/fonts/*.ttf`) and scripts (`assets/brand/embed-fonts.py`, +`render-png.mjs`) are committed for reproducibility. See +[`assets/brand/README.md`](../../assets/brand/README.md). + +## 8. Repository metadata + +Set the GitHub description and topics: + +```bash +gh repo edit --description "Trust-Before-Execution protocol for AI agents and non-human identities." \ + --add-topic ai-agents --add-topic agent-security --add-topic trust \ + --add-topic runtime-governance --add-topic zero-knowledge-proofs \ + --add-topic non-human-identity --add-topic scim --add-topic authorization \ + --add-topic protocol --add-topic execution-receipts \ + --add-topic agent-trust-infrastructure +``` + +## 9. Implementation checklist + +- [x] Color & typography tokens defined +- [x] Hero SVG with embedded brand fonts +- [x] 1280×640 social preview PNG +- [x] Trust-ring motif +- [x] Protocol-loop, trust-gap, decision-matrix diagrams +- [x] Runtime authority flow, trust-decay curve, execution-receipt diagrams +- [x] Architecture stack, integrations, roadmap, contributor-path diagrams +- [x] README rebuilt as a visual landing page +- [x] Grouped badge strip +- [x] Label system + sync workflow +- [x] PR template, discussion templates, FUNDING +- [x] Reproducible font-embed / render build +- [ ] Set repo description + topics (run §8) +- [ ] Upload `assets/social-preview.png` in repo Settings → Social preview +- [ ] Docs site (Starlight/VitePress) — future phase +- [ ] CLI / docs screenshots — future phase diff --git a/package-lock.json b/package-lock.json index ceb098f..4256cd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,9 +7,273 @@ "": { "name": "@blocksifr/ttp-protocol", "version": "0.1.0", + "devDependencies": { + "@fontsource/inter": "^5.2.8", + "@fontsource/jetbrains-mono": "^5.2.8", + "@fontsource/space-grotesk": "^5.2.10", + "@resvg/resvg-js": "^2.6.2" + }, "engines": { "node": ">=18" } + }, + "node_modules/@fontsource/inter": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", + "dev": true, + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/jetbrains-mono": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.2.8.tgz", + "integrity": "sha512-6w8/SG4kqvIMu7xd7wt6x3idn1Qux3p9N62s6G3rfldOUYHpWcc2FKrqf+Vo44jRvqWj2oAtTHrZXEP23oSKwQ==", + "dev": true, + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/space-grotesk": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/@fontsource/space-grotesk/-/space-grotesk-5.2.10.tgz", + "integrity": "sha512-XNXEbT74OIITPqw2H6HXwPDp85fy43uxfBwFR5PU+9sLnjuLj12KlhVM9nZVN6q6dlKjkuN8JisW/OBxwxgUew==", + "dev": true, + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@resvg/resvg-js": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.2.tgz", + "integrity": "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@resvg/resvg-js-android-arm-eabi": "2.6.2", + "@resvg/resvg-js-android-arm64": "2.6.2", + "@resvg/resvg-js-darwin-arm64": "2.6.2", + "@resvg/resvg-js-darwin-x64": "2.6.2", + "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.2", + "@resvg/resvg-js-linux-arm64-gnu": "2.6.2", + "@resvg/resvg-js-linux-arm64-musl": "2.6.2", + "@resvg/resvg-js-linux-x64-gnu": "2.6.2", + "@resvg/resvg-js-linux-x64-musl": "2.6.2", + "@resvg/resvg-js-win32-arm64-msvc": "2.6.2", + "@resvg/resvg-js-win32-ia32-msvc": "2.6.2", + "@resvg/resvg-js-win32-x64-msvc": "2.6.2" + } + }, + "node_modules/@resvg/resvg-js-android-arm-eabi": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz", + "integrity": "sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-android-arm64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz", + "integrity": "sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-darwin-arm64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz", + "integrity": "sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-darwin-x64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz", + "integrity": "sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz", + "integrity": "sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm64-gnu": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz", + "integrity": "sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm64-musl": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz", + "integrity": "sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-x64-gnu": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz", + "integrity": "sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-x64-musl": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz", + "integrity": "sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-arm64-msvc": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz", + "integrity": "sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-ia32-msvc": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz", + "integrity": "sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-x64-msvc": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz", + "integrity": "sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/package.json b/package.json index de067ba..966f7bf 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,15 @@ "test": "node --test tests/*.test.mjs packages/trust-routing-engine/tests/*.test.mjs", "test:ttp": "node --test tests/*.test.mjs", "test:trust-routing": "node --test packages/trust-routing-engine/tests/*.test.mjs", - "check:examples": "node src/index.js check examples/01-basic-agent.ttp && node src/index.js check examples/02-trust-decay.ttp && node src/index.js check examples/03-threshold-proof.ttp && node src/index.js check examples/04-delegated-trust.ttp && node src/index.js check examples/05-agent-tool-trust-wrapper.ttp && node src/index.js check examples/06-cicd-pipeline-trust-proof.ttp && node src/index.js check examples/07-api-client-trust-proof.ttp && node src/index.js check examples/08-msp-mssp-trust-proof.ttp" + "check:examples": "node src/index.js check examples/01-basic-agent.ttp && node src/index.js check examples/02-trust-decay.ttp && node src/index.js check examples/03-threshold-proof.ttp && node src/index.js check examples/04-delegated-trust.ttp && node src/index.js check examples/05-agent-tool-trust-wrapper.ttp && node src/index.js check examples/06-cicd-pipeline-trust-proof.ttp && node src/index.js check examples/07-api-client-trust-proof.ttp && node src/index.js check examples/08-msp-mssp-trust-proof.ttp", + "assets:fonts": "python3 assets/brand/embed-fonts.py", + "assets:social": "node assets/brand/render-png.mjs assets/social-preview.svg assets/social-preview.png 1280", + "assets": "npm run assets:fonts && npm run assets:social" + }, + "devDependencies": { + "@fontsource/inter": "^5.2.8", + "@fontsource/jetbrains-mono": "^5.2.8", + "@fontsource/space-grotesk": "^5.2.10", + "@resvg/resvg-js": "^2.6.2" } } From a3115d57a270459a71809c3d84dcd5232cc5723f Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Thu, 25 Jun 2026 22:19:22 -0400 Subject: [PATCH 3/7] Add VitePress docs site and branded screenshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - website/: dark-first VitePress docs site on the TTP design system — brand tokens, custom protocol callouts (AUTHORITY/ATTESTATION/DECAY/ RECEIPT/STEP-UP/DENY), "choose your path" home cards, full nav/sidebar, and pages for concepts, runtime, decay, proofs, receipts, language, examples, integrations, RFCs, contributing, security. Builds clean. - assets/screenshots/: branded cli-demo terminal (from real `ttp check` output) and receipt-preview, rendered with embedded brand fonts. Co-Authored-By: Claude Opus 4.8 --- assets/screenshots/cli-demo.png | Bin 0 -> 22794 bytes assets/screenshots/cli-demo.svg | 36 + assets/screenshots/receipt-preview.png | Bin 0 -> 30849 bytes docs/brand/VISUAL_DESIGN.md | 7 +- website/.vitepress/config.mjs | 91 + website/.vitepress/theme/custom.css | 110 + website/.vitepress/theme/index.mjs | 4 + website/guide/concepts.md | 45 + website/guide/contributing.md | 24 + website/guide/decay.md | 35 + website/guide/examples.md | 20 + website/guide/integrations.md | 24 + website/guide/language.md | 27 + website/guide/proofs.md | 25 + website/guide/receipts.md | 28 + website/guide/rfcs.md | 23 + website/guide/runtime.md | 37 + website/guide/security.md | 33 + website/guide/start.md | 34 + website/index.md | 65 + website/package-lock.json | 2519 +++++++++++++++++ website/package.json | 14 + .../public/diagrams/architecture-stack.svg | 48 + website/public/diagrams/contributor-path.svg | 23 + website/public/diagrams/decision-matrix.svg | 60 + website/public/diagrams/execution-receipt.svg | 41 + website/public/diagrams/integrations.svg | 20 + website/public/diagrams/protocol-loop.svg | 29 + website/public/diagrams/roadmap.svg | 50 + .../diagrams/runtime-authority-flow.svg | 70 + website/public/diagrams/trust-decay-curve.svg | 53 + website/public/diagrams/trust-gap.svg | 49 + website/public/repo-icon.svg | 12 + website/public/social-preview.png | Bin 0 -> 131109 bytes website/public/trust-ring.svg | 26 + website/public/ttp-hero.svg | 87 + 36 files changed, 3767 insertions(+), 2 deletions(-) create mode 100644 assets/screenshots/cli-demo.png create mode 100644 assets/screenshots/cli-demo.svg create mode 100644 assets/screenshots/receipt-preview.png create mode 100644 website/.vitepress/config.mjs create mode 100644 website/.vitepress/theme/custom.css create mode 100644 website/.vitepress/theme/index.mjs create mode 100644 website/guide/concepts.md create mode 100644 website/guide/contributing.md create mode 100644 website/guide/decay.md create mode 100644 website/guide/examples.md create mode 100644 website/guide/integrations.md create mode 100644 website/guide/language.md create mode 100644 website/guide/proofs.md create mode 100644 website/guide/receipts.md create mode 100644 website/guide/rfcs.md create mode 100644 website/guide/runtime.md create mode 100644 website/guide/security.md create mode 100644 website/guide/start.md create mode 100644 website/index.md create mode 100644 website/package-lock.json create mode 100644 website/package.json create mode 100644 website/public/diagrams/architecture-stack.svg create mode 100644 website/public/diagrams/contributor-path.svg create mode 100644 website/public/diagrams/decision-matrix.svg create mode 100644 website/public/diagrams/execution-receipt.svg create mode 100644 website/public/diagrams/integrations.svg create mode 100644 website/public/diagrams/protocol-loop.svg create mode 100644 website/public/diagrams/roadmap.svg create mode 100644 website/public/diagrams/runtime-authority-flow.svg create mode 100644 website/public/diagrams/trust-decay-curve.svg create mode 100644 website/public/diagrams/trust-gap.svg create mode 100644 website/public/repo-icon.svg create mode 100644 website/public/social-preview.png create mode 100644 website/public/trust-ring.svg create mode 100644 website/public/ttp-hero.svg diff --git a/assets/screenshots/cli-demo.png b/assets/screenshots/cli-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..9ae07143d65ebabccf9e3f35e9cdef0b2118b144 GIT binary patch literal 22794 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 literal 0 HcmV?d00001 diff --git a/assets/screenshots/cli-demo.svg b/assets/screenshots/cli-demo.svg new file mode 100644 index 0000000..e3bb924 --- /dev/null +++ b/assets/screenshots/cli-demo.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + ttp — trust check + + + $ttp check examples/01-basic-agent.ttp + + + + { + "ok": true, + "file": "examples/01-basic-agent.ttp", + "subjects": 1, + "trust_claims": 1, + "proofs": 1, + "authority_contexts": 1, + "delegations": 0 + } + + + + VALID · 1 subject · 1 proof + diff --git a/assets/screenshots/receipt-preview.png b/assets/screenshots/receipt-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..4c69fbc0a9bce99c03a36c63506c0f86444b75b6 GIT binary patch literal 30849 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 Vd!HNc!AF7prKNYZP~+C4{{r$?aG3xA literal 0 HcmV?d00001 diff --git a/docs/brand/VISUAL_DESIGN.md b/docs/brand/VISUAL_DESIGN.md index 19ed1db..9965999 100644 --- a/docs/brand/VISUAL_DESIGN.md +++ b/docs/brand/VISUAL_DESIGN.md @@ -126,7 +126,10 @@ gh repo edit --description "Trust-Before-Execution protocol for AI agents and no - [x] Label system + sync workflow - [x] PR template, discussion templates, FUNDING - [x] Reproducible font-embed / render build +- [x] Docs site — VitePress under `website/` (dark-first, brand tokens, custom + protocol callouts, "choose your path" cards); builds clean +- [x] Screenshots — `assets/screenshots/cli-demo.png`, `receipt-preview.png` - [ ] Set repo description + topics (run §8) - [ ] Upload `assets/social-preview.png` in repo Settings → Social preview -- [ ] Docs site (Starlight/VitePress) — future phase -- [ ] CLI / docs screenshots — future phase +- [ ] `docs-home.png` screenshot — needs a headless browser to capture the + rendered docs site (`cd website && npm run docs:dev`) diff --git a/website/.vitepress/config.mjs b/website/.vitepress/config.mjs new file mode 100644 index 0000000..2e10943 --- /dev/null +++ b/website/.vitepress/config.mjs @@ -0,0 +1,91 @@ +import { defineConfig } from "vitepress"; +import container from "markdown-it-container"; + +// Custom protocol callouts: ::: authority / attestation / decay / receipt / step-up / deny +const CALLOUTS = { + authority: "AUTHORITY", + attestation: "ATTESTATION", + decay: "DECAY", + receipt: "RECEIPT", + "step-up": "STEP-UP", + deny: "DENY", +}; + +function calloutPlugin(md) { + for (const [name, label] of Object.entries(CALLOUTS)) { + md.use(container, name, { + render(tokens, idx) { + const token = tokens[idx]; + if (token.nesting === 1) { + const title = token.info.trim().slice(name.length).trim() || label; + return `

    ${md.utils.escapeHtml(title)}

    \n`; + } + return "
    \n"; + }, + }); + } +} + +export default defineConfig({ + title: "Trust Transfer Protocol", + description: "Trust-Before-Execution for AI agents and non-human identities.", + appearance: "dark", + cleanUrls: true, + ignoreDeadLinks: true, + head: [ + ["meta", { name: "theme-color", content: "#0A0A0F" }], + ["meta", { property: "og:image", content: "/social-preview.png" }], + ], + markdown: { + theme: { light: "github-dark", dark: "github-dark" }, + languageAlias: { ttp: "hcl" }, + config: (md) => calloutPlugin(md), + }, + themeConfig: { + logo: "/repo-icon.svg", + nav: [ + { text: "Start", link: "/guide/start" }, + { text: "Concepts", link: "/guide/concepts" }, + { text: "Runtime", link: "/guide/runtime" }, + { text: "Receipts", link: "/guide/receipts" }, + { text: "Spec", link: "https://github.com/BlockSiFr/ttp-protocol/blob/main/SPECIFICATION.md" }, + ], + sidebar: [ + { + text: "Start", + items: [ + { text: "Overview", link: "/guide/start" }, + { text: "Quickstart", link: "/guide/start#quickstart" }, + ], + }, + { + text: "Protocol", + items: [ + { text: "Concepts", link: "/guide/concepts" }, + { text: "Language Specification", link: "/guide/language" }, + { text: "Runtime Authority", link: "/guide/runtime" }, + { text: "Trust Decay", link: "/guide/decay" }, + { text: "Proofs", link: "/guide/proofs" }, + { text: "Execution Receipts", link: "/guide/receipts" }, + ], + }, + { + text: "Build", + items: [ + { text: "Examples", link: "/guide/examples" }, + { text: "Integrations", link: "/guide/integrations" }, + { text: "RFCs", link: "/guide/rfcs" }, + { text: "Contributing", link: "/guide/contributing" }, + { text: "Security", link: "/guide/security" }, + ], + }, + ], + socialLinks: [ + { icon: "github", link: "https://github.com/BlockSiFr/ttp-protocol" }, + ], + footer: { + message: "Apache-2.0 · A BlockSiFr open protocol", + copyright: "Trust-Before-Execution for autonomous systems", + }, + }, +}); diff --git a/website/.vitepress/theme/custom.css b/website/.vitepress/theme/custom.css new file mode 100644 index 0000000..3db0e13 --- /dev/null +++ b/website/.vitepress/theme/custom.css @@ -0,0 +1,110 @@ +/* TTP docs theme — dark, precise, cryptographic. Maps the brand token system + onto VitePress. Brand fonts load as webfonts (allowed on the docs site). */ +@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap"); + +:root { + --vp-font-family-base: "Inter", system-ui, sans-serif; + --vp-font-family-mono: "JetBrains Mono", ui-monospace, monospace; + + --ttp-black: #0a0a0f; + --ttp-panel: #12141c; + --ttp-card: #101521; + --ttp-border: #1e2430; + --ttp-cyan: #00d4ff; + --ttp-azure: #0066cc; + --ttp-white: #f0f2f5; + --ttp-steel: #8892a0; + --ttp-green: #00e676; + --ttp-teal: #00b8a9; + --ttp-amber: #ffb300; + --ttp-red: #ff3d00; + + /* brand accent */ + --vp-c-brand-1: var(--ttp-cyan); + --vp-c-brand-2: #5fe3ff; + --vp-c-brand-3: var(--ttp-azure); + --vp-c-brand-soft: rgba(0, 212, 255, 0.12); +} + +.dark { + --vp-c-bg: var(--ttp-black); + --vp-c-bg-alt: #0b0d13; + --vp-c-bg-soft: var(--ttp-card); + --vp-c-bg-elv: var(--ttp-panel); + --vp-c-border: var(--ttp-border); + --vp-c-divider: var(--ttp-border); + --vp-c-text-1: var(--ttp-white); + --vp-c-text-2: #c2cad6; + --vp-c-text-3: var(--ttp-steel); + + --vp-code-block-bg: #0a0a0f; + --vp-code-bg: rgba(0, 212, 255, 0.07); + --vp-code-color: #c2cad6; +} + +/* Display type */ +h1, h2, h3, .VPHero .name, .VPHero .text { + font-family: "Space Grotesk", "Inter", system-ui, sans-serif; + letter-spacing: -0.02em; +} +h2 { + border-top: 1px solid var(--ttp-border); + padding-top: 1.5rem; +} + +/* Hero */ +.VPHero .name { color: var(--ttp-white); } +.VPHero .text { color: var(--ttp-cyan); } +.VPHero .tagline { color: var(--ttp-steel); } +.VPHero .image-bg { display: none; } + +/* Feature / path cards */ +.VPFeature { + background: var(--ttp-card); + border: 1px solid var(--ttp-border); + transition: border-color 0.15s ease; +} +.VPFeature:hover { border-color: rgba(0, 212, 255, 0.4); } +.VPFeature .icon { + background: transparent !important; + font-size: 22px; +} + +/* Code blocks — thin border, mono */ +div[class*="language-"] { + border: 1px solid var(--ttp-border); + border-radius: 10px; + background: #0a0a0f; +} +div[class*="language-"] code { font-size: 13px; } + +/* Custom protocol callouts */ +.ttp-callout { + margin: 18px 0; + padding: 14px 18px 14px 16px; + border: 1px solid var(--ttp-border); + border-left-width: 3px; + border-radius: 8px; + background: var(--ttp-card); +} +.ttp-callout-title { + margin: 0 0 6px; + font-family: "JetBrains Mono", ui-monospace, monospace; + font-size: 11px; + letter-spacing: 2px; + font-weight: 500; +} +.ttp-callout :last-child { margin-bottom: 0; } + +.ttp-authority { border-left-color: var(--ttp-azure); } +.ttp-authority .ttp-callout-title { color: var(--ttp-azure); } +.ttp-attestation { border-left-color: var(--ttp-teal); } +.ttp-attestation .ttp-callout-title { color: var(--ttp-teal); } +.ttp-decay { border-left-color: var(--ttp-cyan); } +.ttp-decay .ttp-callout-title { color: var(--ttp-cyan); } +.ttp-receipt { border-left-color: var(--ttp-green); } +.ttp-receipt .ttp-callout-title { color: var(--ttp-green); } +.ttp-step-up { border-left-color: var(--ttp-amber); } +.ttp-step-up .ttp-callout-title { color: var(--ttp-amber); } +.ttp-deny { border-left-color: var(--ttp-red); } +.ttp-deny .ttp-callout-title { color: var(--ttp-red); } diff --git a/website/.vitepress/theme/index.mjs b/website/.vitepress/theme/index.mjs new file mode 100644 index 0000000..c495bc1 --- /dev/null +++ b/website/.vitepress/theme/index.mjs @@ -0,0 +1,4 @@ +import DefaultTheme from "vitepress/theme"; +import "./custom.css"; + +export default DefaultTheme; diff --git a/website/guide/concepts.md b/website/guide/concepts.md new file mode 100644 index 0000000..d139361 --- /dev/null +++ b/website/guide/concepts.md @@ -0,0 +1,45 @@ +# Protocol Concepts + +TTP is built from a small set of primitives that compose into a verifiable +trust decision. + +

    + Protocol loop +

    + +## Primitives + +| Primitive | Meaning | +| --- | --- | +| **Subject** | The agent, service account, pipeline, API client, or workflow being evaluated. | +| **TrustClaim** | A scoped statement that a Subject holds a trust score, issued by a trust issuer. | +| **AuthorityGrant** | A bounded right relied on only when trust, freshness, and scope are satisfied. | +| **Attestation** | Fresh evidence that the subject or runtime context remains valid. | +| **TrustDecay** | Time-based weakening of trust when fresh evidence is absent. | +| **Delegation** | Bounded transfer of trust or authority from one subject to another. | +| **IsnadChain** | A verifiable chain of trust transmission from a rooted authority to the actor. | +| **TrustProof** | A structured proof that trust conditions were evaluated and satisfied. | +| **ExecutionReceipt** | A signed proof object recording the decision and its basis. | + +::: authority AUTHORITY +An `AuthorityGrant` is never trusted on its own. It is only relied on when the +current trust score clears the policy threshold, the grant is in scope, and its +evidence is fresh. +::: + +::: attestation ATTESTATION +An `Attestation` is fresh evidence — a signed claim that the subject, code, +workload, or runtime is still valid. Attestations recharge trust. +::: + +::: decay DECAY +Trust is not permanent. Without new attestations it decays through +`active → degraded → warning → critical`. See [Trust Decay](/guide/decay). +::: + +## How they compose + +A request carries an identity. TTP gathers trust claims and attestations, +applies decay, and produces a `TrustProof`. A runtime authority gate combines +the proof with an `AuthorityGrant` and emits a decision plus an +`ExecutionReceipt`. diff --git a/website/guide/contributing.md b/website/guide/contributing.md new file mode 100644 index 0000000..1e2a11b --- /dev/null +++ b/website/guide/contributing.md @@ -0,0 +1,24 @@ +# Contributing + +From a first issue to owning a protocol surface — the path is open and +intentional. + +

    + Contributor path +

    + +| Step | Do this | +| --- | --- | +| Start Here | Read the README and [Concepts](/guide/concepts). | +| Good First Issue | Pick a small, scoped task labeled `status: good first issue`. | +| Protocol RFC | Propose a change via an [RFC](/guide/rfcs). | +| Runtime Implementation | Build enforcement at a real surface. | +| Docs + Examples | Teach the next developer. | +| Maintainer Path | Own a protocol surface. | + +See [CONTRIBUTING.md](https://github.com/BlockSiFr/ttp-protocol/blob/main/CONTRIBUTING.md) +and [GOVERNANCE.md](https://github.com/BlockSiFr/ttp-protocol/blob/main/GOVERNANCE.md). + +::: receipt ROADMAP +Roadmap phases +::: diff --git a/website/guide/decay.md b/website/guide/decay.md new file mode 100644 index 0000000..5fcc5bd --- /dev/null +++ b/website/guide/decay.md @@ -0,0 +1,35 @@ +# Trust Decay + +Trust is a function of time and evidence. Without fresh attestation it weakens; +a new attestation recharges it. + +

    + Trust decay and attestation recharge +

    + +## Bands + +| Band | Range | Posture | +| --- | --- | --- | +| Active | `0.85–1.00` | Full reliance | +| Degraded | `0.65–0.85` | Reliance with watch | +| Warning | `0.40–0.65` | Step-up before sensitive actions | +| Critical | `0.00–0.40` | Deny by default | + +```ttp +trust "invoice_agent" { + subject = agent:invoice-bot + score = 0.91 + decay = exponential(halflife = 6h) # trust halves every 6h without evidence +} +``` + +::: decay DECAY +Decay is declarative. Choose a model (`exponential`, `linear`, `stepped`) and a +rate; the evaluator applies it at proof time against the elapsed interval. +::: + +::: attestation ATTESTATION +A verified attestation adds a recharge delta, lifting the effective score back +toward the active band. +::: diff --git a/website/guide/examples.md b/website/guide/examples.md new file mode 100644 index 0000000..4170516 --- /dev/null +++ b/website/guide/examples.md @@ -0,0 +1,20 @@ +# Examples + +Runnable `.ttp` examples live in the +[`examples/`](https://github.com/BlockSiFr/ttp-protocol/tree/main/examples) +directory. Validate any of them with `npm run ttp -- check `. + +| Example | Shows | +| --- | --- | +| `01-basic-agent.ttp` | A minimal subject + trust claim. | +| `02-trust-decay.ttp` | Trust decaying over time. | +| `03-threshold-proof.ttp` | Proving trust clears a threshold. | +| `04-delegated-trust.ttp` | Bounded delegation between subjects. | +| `05-agent-tool-trust-wrapper.ttp` | Gating an agent tool call. | +| `06-cicd-pipeline-trust-proof.ttp` | Trust before a deploy stage. | +| `07-api-client-trust-proof.ttp` | Gating a sensitive API client. | +| `08-msp-mssp-trust-proof.ttp` | Customer-impacting operational action. | + +```bash +npm run ttp -- eval examples/02-trust-decay.ttp --subject agent:invoice_reviewer --at now +``` diff --git a/website/guide/integrations.md b/website/guide/integrations.md new file mode 100644 index 0000000..e9af8c0 --- /dev/null +++ b/website/guide/integrations.md @@ -0,0 +1,24 @@ +# Integrations + +TTP wraps the boundary where an action happens — no agent rewrite, no IdP +replacement. The enforcement point and current status by surface: + +

    + Integration surfaces and status +

    + +| Surface | Enforcement point | Status | +| --- | --- | --- | +| GitHub Actions | workflow job | reference | +| CI/CD Pipelines | pipeline stage | reference | +| API Gateways | gateway request | experimental | +| Service Accounts | token issuance | experimental | +| Microsoft Copilot | tool call | planned | +| Azure DevOps | release stage | planned | +| LangChain | agent tool | experimental | +| CrewAI | agent step | planned | + +::: authority PATTERN +Each integration evaluates a `TrustProof` at the surface's action point and +records an [ExecutionReceipt](/guide/receipts) for the decision. +::: diff --git a/website/guide/language.md b/website/guide/language.md new file mode 100644 index 0000000..a48bd84 --- /dev/null +++ b/website/guide/language.md @@ -0,0 +1,27 @@ +# Language Specification + +TTP is expressed as a small declarative language. A `.ttp` file declares +subjects, their trust, and the policies that gate actions. + +```ttp +trust "invoice_agent" { + subject = agent:invoice-bot + issuer = trust-issuer:finance-control + score = 0.91 + decay = exponential(halflife = 6h) + scope = [invoice.read, invoice.write] + evidence = [attestation:att-7b3c, receipt:rcpt-01J9F4] +} + +policy "write_invoices" { + action = invoice.write + require_trust = 0.80 + on_below = step-up + execution_policy = gate + emit = execution_receipt +} +``` + +The full grammar, evaluation order, and failure codes are in the +[SPECIFICATION.md](https://github.com/BlockSiFr/ttp-protocol/blob/main/SPECIFICATION.md). +Validate a file with `npm run ttp -- check `. diff --git a/website/guide/proofs.md b/website/guide/proofs.md new file mode 100644 index 0000000..b1c478d --- /dev/null +++ b/website/guide/proofs.md @@ -0,0 +1,25 @@ +# Proofs + +A `TrustProof` is the structured output of evaluating a subject's trust against +a requirement. It composes sub-proofs — threshold, attestations, delegation, +route, and decay — into a single verifiable envelope with a `proofHash`. + +## Outcomes + +| Outcome | Meaning | +| --- | --- | +| `trust_valid` | Current evidence satisfies the requirement. | +| `trust_insufficient` | Effective trust is below the threshold. | +| `trust_expired` | A claim or proof freshness window has elapsed. | +| `trust_invalid` | Issuer, evidence, reference, or validation failed. | +| `trust_unknown` | Trust cannot be established from available evidence. | + +## Proof modes + +`plain` · `signed` · `zk-placeholder` · `zk`. Production proofs must be `signed` +or `zk`; never rely on `cleartext-dev` outside local development. + +::: receipt PROOF +A proof is the input to a runtime decision. The decision and its proof reference +are then recorded together in an [ExecutionReceipt](/guide/receipts). +::: diff --git a/website/guide/receipts.md b/website/guide/receipts.md new file mode 100644 index 0000000..c6f56c3 --- /dev/null +++ b/website/guide/receipts.md @@ -0,0 +1,28 @@ +# Execution Receipts + +Every decision produces a signed, hash-chained `ExecutionReceipt` — evidence, +not a log line. It records what was decided, the trust state behind it, and the +cryptographic basis to verify it later. + +

    + Execution receipt card +

    + +## Fields + +| Field | Meaning | +| --- | --- | +| `subject` | The actor that was evaluated. | +| `action` / `resource` | What was attempted, and against what. | +| `decision` | `allow` · `throttle` · `step-up` · `escalate` · `deny`. | +| `trustScoreAtDecision` | Effective trust at the moment of decision. | +| `authorityGrantRef` | The grant relied upon. | +| `attestationRef` | The evidence that supported trust. | +| `timestamp` | When the decision was made. | +| `signature` | Cryptographic signature over the receipt. | +| `chainHash` | Links this receipt to the prior one — tamper-evident. | + +::: receipt RECEIPT +A receipt is verifiable independently of the system that produced it. Given the +public key and the chain, anyone can confirm the decision was made as recorded. +::: diff --git a/website/guide/rfcs.md b/website/guide/rfcs.md new file mode 100644 index 0000000..ca4d2a2 --- /dev/null +++ b/website/guide/rfcs.md @@ -0,0 +1,23 @@ +# RFCs + +Protocol changes are proposed as RFCs in the +[`rfcs/`](https://github.com/BlockSiFr/ttp-protocol/tree/main/rfcs) directory. +Anything that touches the grammar, semantics, schemas, or trust model needs one. + +## Process + +1. Open a **Protocol RFC** discussion to socialize the idea. +2. Draft an RFC from `rfcs/0000-template.md`. +3. Open a PR; mark it `status: needs-rfc` until accepted. +4. On acceptance, the change lands with tests and docs. + +| RFC | Topic | +| --- | --- | +| 0001 | Authority grants | +| 0002 | Execution receipts | +| 0003 | Trust decay | +| 0004 | Attestations | +| 0005 | Trust proof outcomes | +| 0006 | Runtime decisions | +| 0007 | Agent trust wrapper | +| 0008 | Commercial boundary | diff --git a/website/guide/runtime.md b/website/guide/runtime.md new file mode 100644 index 0000000..e1a1aa8 --- /dev/null +++ b/website/guide/runtime.md @@ -0,0 +1,37 @@ +# Runtime Authority + +Trust is checked at a **runtime authority gate** before an action runs. The gate +consumes a trust proof, an authority grant, and the current decay state, then +emits a decision and a signed receipt. + +

    + Runtime authority flow +

    + +## Decision outcomes + +

    + allow, throttle, step-up, escalate, deny +

    + +| Outcome | Meaning | +| --- | --- | +| `allow` | Trust clears the threshold; the action executes. | +| `throttle` | Marginal trust; proceed under rate or scope limits. | +| `step-up` | Fresh attestation required to continue. | +| `escalate` | Route to a human or higher authority for review. | +| `deny` | Trust below floor; the action is blocked. | + +::: deny DENY +The gate is **fail-closed**. If trust cannot be established, the default outcome +is `deny` — never implicit allow. +::: + +::: step-up STEP-UP +A `step-up` is not a failure. It asks the actor to present fresh evidence (a new +attestation) and re-enter the gate. +::: + +> TTP establishes the trust context. RAP, Execution Exchange, API gateways, and +> CI gates enforce the decision. See the +> [commercial boundary](https://github.com/BlockSiFr/ttp-protocol/blob/main/COMMERCIAL_BOUNDARY.md). diff --git a/website/guide/security.md b/website/guide/security.md new file mode 100644 index 0000000..a2a8783 --- /dev/null +++ b/website/guide/security.md @@ -0,0 +1,33 @@ +# Security + +TTP is a protocol draft and reference implementation. + +::: deny DO NOT +Do not use `cleartext-dev` proof mode in production. It performs no +cryptographic verification and exists only for local development. +::: + +## Production requirements + +Production trust establishment and downstream enforcement require: + +- trusted issuer registry +- signed claims and replay protection +- clock integrity and key rotation +- tenant isolation +- **fail-closed** downstream enforcement +- receipt signing and audit retention +- attestation freshness and evidence integrity + +## Posture + +| Property | Status | +| --- | --- | +| Spec | draft v1.0 | +| Reference evaluator | active | +| Production enforcement | commercial (Execution Exchange) | + +Report vulnerabilities per +[SECURITY.md](https://github.com/BlockSiFr/ttp-protocol/blob/main/SECURITY.md). +The full threat model is in +[THREAT_MODEL.md](https://github.com/BlockSiFr/ttp-protocol/blob/main/THREAT_MODEL.md). diff --git a/website/guide/start.md b/website/guide/start.md new file mode 100644 index 0000000..e34e4cd --- /dev/null +++ b/website/guide/start.md @@ -0,0 +1,34 @@ +# Overview + +The **Trust Transfer Protocol (TTP)** is the protocol layer for agent trust. +Identity proves *who* is acting. Authorization defines *what* was assigned. TTP +establishes whether the actor is **trustworthy enough for this action, right +now** — before any downstream authority or execution decision is made. + +

    + Identity vs Authorization vs TTP +

    + +## Quickstart + +```bash +git clone https://github.com/BlockSiFr/ttp-protocol.git +cd ttp-protocol +npm install +npm test + +# evaluate the reference examples +npm run ttp -- check examples/01-basic-agent.ttp +npm run ttp -- eval examples/02-trust-decay.ttp --subject agent:invoice_reviewer --at now +npm run demo +``` + +- `check` validates a `.ttp` file. +- `eval` evaluates a subject's trust at a point in time. +- `demo` prints reference decisions, trust scores, and `ExecutionReceipt` ids + for local, non-production scenarios. + +::: receipt NEXT +Continue to [Protocol Concepts](/guide/concepts) to learn the primitives, then +[Runtime Authority](/guide/runtime) for how decisions are made. +::: diff --git a/website/index.md b/website/index.md new file mode 100644 index 0000000..41e0d12 --- /dev/null +++ b/website/index.md @@ -0,0 +1,65 @@ +--- +layout: home +hero: + name: Trust Transfer Protocol + text: Trust-Before-Execution + tagline: Every action must earn authority before execution. Every decision must be provable after. + image: + src: /trust-ring.svg + alt: TTP trust ring + actions: + - theme: brand + text: Quickstart + link: /guide/start + - theme: alt + text: Protocol Concepts + link: /guide/concepts + - theme: alt + text: GitHub + link: https://github.com/BlockSiFr/ttp-protocol +features: + - icon: ▣ + title: I'm an AI engineer + details: Wrap agent tool calls with a trust proof — no rewrite required. + link: /guide/integrations + - icon: ◆ + title: I'm a security architect + details: Fail-closed runtime gating, signed receipts, and a threat model. + link: /guide/security + - icon: ⬡ + title: I'm building an agent framework + details: Embed the runtime authority gate at your execution boundary. + link: /guide/runtime + - icon: ▤ + title: I'm evaluating enterprise governance + details: Where the open protocol ends and managed enforcement begins. + link: /guide/concepts + - icon: ✦ + title: I want to contribute + details: From a good first issue to owning a protocol surface. + link: /guide/contributing +--- + +

    + Identity, Attestation, Trust Evaluation, Runtime Authority Gate, Decision, Execution Receipt +

    + +## Protocol status + +::: decay PROTOCOL v1.0 · REFERENCE EVALUATOR ACTIVE +The protocol spec and reference evaluator are available. Runtime authority +enforcement is in progress. Do not use `cleartext-dev` proof mode in production. +::: + +## Quickstart + +```bash +git clone https://github.com/BlockSiFr/ttp-protocol.git +cd ttp-protocol && npm install && npm test + +npm run ttp -- check examples/01-basic-agent.ttp +npm run demo +``` + +Then read [Protocol Concepts](/guide/concepts) and the +[Runtime Authority](/guide/runtime) model. diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 0000000..26d3782 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,2519 @@ +{ + "name": "@blocksifr/ttp-docs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@blocksifr/ttp-docs", + "devDependencies": { + "markdown-it-container": "^4.0.0", + "vitepress": "^1.6.3" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.21.1.tgz", + "integrity": "sha512-Wia5/mNTfiU0PIUN25UMfAGGdASkkwuCS9nBAdmhqrNPY/ff7U/6MgBVdwFDPsa3sA1msutPtO50gvOzx6MOXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.55.1.tgz", + "integrity": "sha512-miW8RzAtBgNiEJ9fGEhsOPgWUpekAe64YcVufqXrlykj0Jjmo5nj0a5f/HAzRVX5ZuU1GAVd7BkzFDx7q50P3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.55.1.tgz", + "integrity": "sha512-eR3J3kB9JX6DdCvDRi3I4KPfwO6fR9HWYRXhVke2TXIoOQafMKCRAneg33JRmIrb+DnnJ/eWApJLF1O1CLPERg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.55.1.tgz", + "integrity": "sha512-OVtj9uA//+pjvKQI5INnzbyLrf3ClNv3XRbWswwJ2kHIStQNHtBfHo+LofNB/WhM9xjuXlW5ANn2aMj65UGx7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.55.1.tgz", + "integrity": "sha512-oKlVFlp+qbIEe4p7E54zSiP2gEV/vDu972Ykv8VDMFwEvreS7m0YKA3a8hGGHwc7yiBUGGiR3LlwzMLfnJmy6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.55.1.tgz", + "integrity": "sha512-BOVrld6vdtsFmotVDMTVQfYXwrVplJ+DUvy60JFi+tkWV698q2J9NNPKEO3dr5qxtSLKQP4vHF8n+3U5PDWhOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.55.1.tgz", + "integrity": "sha512-GAqHl9zERhC3bbBfubwUu07G3UXO06gORvOcsiTBZB3et0s3auNUbHlYdYNp4VKa3sUZqH5AcD3OKzU/KDGXjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.55.1.tgz", + "integrity": "sha512-BXZw+C+gsWL7pZvbnhJUnCXASiDLGcQxVV7h55Pyh2DmSzwdZIVccE5xc9RVD2trtrhIqk5smuODTxtaZqd0IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.55.1.tgz", + "integrity": "sha512-9g/ceZrZTqA62FA3588Xj0onRPjDNfu0pVQqefK0rrHp9H6Wblph/YmzGjZ2g8uqbTh0ZGIvAGCzErU8f7MHpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.55.1.tgz", + "integrity": "sha512-cZTIrGyAP+W4A6jDVwvWM/JOaoJKQkD/2a5eLUEeNdKAD45jN7BCpsMDONyhZlosLa4UwL8uiINQzj4iFy9nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.55.1.tgz", + "integrity": "sha512-N6I3leW0UO8Y9Zv90yo2UHgYGuxZO0mjbvzNxDIJDjO0qECEF7Z9XMvSNeUWXQh/iNDA9lr8MfEy3rmZGIcclw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.55.1.tgz", + "integrity": "sha512-ukU5zeeFs44rQkzv+TRdYard+d+3lmPGs8lPZhHtWE8rfz+LlBSF6s9kP3VQ7LeOYL8Dz0u6tZfnyTrqrumbHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.55.1.tgz", + "integrity": "sha512-lCwXyijwPm3vbYHpBXPRomMcD6mgiptmps27gnMCf4HK+u/AOeFPBnIFh4V3l4A5SnP9VRiKBZqwGBpUH0vaTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.87", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.87.tgz", + "integrity": "sha512-8YciStObhSji3OZFmWAWK6kBujyqO5bLCxeDwLxf3CR3F4PVelq7keC2LBvgTqviWzSTysj5/g4PCFLiAMVGsw==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.2.tgz", + "integrity": "sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.39.tgz", + "integrity": "sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.39", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.39.tgz", + "integrity": "sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.39", + "@vue/shared": "3.5.39" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.39.tgz", + "integrity": "sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.39", + "@vue/compiler-dom": "3.5.39", + "@vue/compiler-ssr": "3.5.39", + "@vue/shared": "3.5.39", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.15", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.39.tgz", + "integrity": "sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.39", + "@vue/shared": "3.5.39" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz", + "integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.10" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz", + "integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.10", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz", + "integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.39.tgz", + "integrity": "sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.39" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.39.tgz", + "integrity": "sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.39", + "@vue/shared": "3.5.39" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.39.tgz", + "integrity": "sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.39", + "@vue/runtime-core": "3.5.39", + "@vue/shared": "3.5.39", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.39.tgz", + "integrity": "sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.39", + "@vue/shared": "3.5.39" + }, + "peerDependencies": { + "vue": "3.5.39" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.39.tgz", + "integrity": "sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/algoliasearch": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.55.1.tgz", + "integrity": "sha512-FyaFnnsbVPtevQwqSj/SdxE3jAsSsY0BEH8IVLf9rXxEBdAhAmT6VKCVSMWoaPIHVN1Eufh/1w8q6k8URpIkWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.21.1", + "@algolia/client-abtesting": "5.55.1", + "@algolia/client-analytics": "5.55.1", + "@algolia/client-common": "5.55.1", + "@algolia/client-insights": "5.55.1", + "@algolia/client-personalization": "5.55.1", + "@algolia/client-query-suggestions": "5.55.1", + "@algolia/client-search": "5.55.1", + "@algolia/ingestion": "1.55.1", + "@algolia/monitoring": "1.55.1", + "@algolia/recommend": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.4.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdown-it-container": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-4.0.0.tgz", + "integrity": "sha512-HaNccxUH0l7BNGYbFbjmGpf5aLHAMTinqRZQAEQbMr2cdD3z91Q6kIo1oUn1CQndkT03jat6ckrdRYuwwqLlQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.29.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.2.tgz", + "integrity": "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz", + "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.39.tgz", + "integrity": "sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.39", + "@vue/compiler-sfc": "3.5.39", + "@vue/runtime-dom": "3.5.39", + "@vue/server-renderer": "3.5.39", + "@vue/shared": "3.5.39" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000..4a5d5a4 --- /dev/null +++ b/website/package.json @@ -0,0 +1,14 @@ +{ + "name": "@blocksifr/ttp-docs", + "private": true, + "type": "module", + "scripts": { + "docs:dev": "vitepress dev", + "docs:build": "vitepress build", + "docs:preview": "vitepress preview" + }, + "devDependencies": { + "markdown-it-container": "^4.0.0", + "vitepress": "^1.6.3" + } +} diff --git a/website/public/diagrams/architecture-stack.svg b/website/public/diagrams/architecture-stack.svg new file mode 100644 index 0000000..8c54914 --- /dev/null +++ b/website/public/diagrams/architecture-stack.svg @@ -0,0 +1,48 @@ + + + + + + + + + + L4 + Consumers + Agent frameworks · CI/CD · APIs · Copilots + + + + + L3 + Execution Exchange + Enterprise control plane · evidence & receipts + + + + + L2 + Runtime Authority Gate + Decides allow · step-up · deny before execution + + + + + L1 + SCIM-RE · Runtime Governance + Authority grants · policy · runtime execution context + + + + + + L0 + Trust Transfer Protocol + Trust scoring · decay · delegation · proofs · receipts + FOUNDATION + + diff --git a/website/public/diagrams/contributor-path.svg b/website/public/diagrams/contributor-path.svg new file mode 100644 index 0000000..7f78ce4 --- /dev/null +++ b/website/public/diagrams/contributor-path.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + 01Start HereREADME & concepts + 02Good First Issuesmall, scoped tasks + 03Protocol RFCpropose a change + 04Runtime Implbuild enforcement + 05Docs + Examplesteach the next dev + 06Maintainer Pathown a surface + diff --git a/website/public/diagrams/decision-matrix.svg b/website/public/diagrams/decision-matrix.svg new file mode 100644 index 0000000..7563983 --- /dev/null +++ b/website/public/diagrams/decision-matrix.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + allow + Trust clears threshold. + Action executes. + PROCEED + + + + + + + throttle + Marginal trust. + Rate-limit the actor. + SLOW + + + + + + + step-up + Fresh attestation + required to continue. + RE-PROVE + + + + + + + escalate + Route to a human + authority for review. + REVIEW + + + + + + + deny + Trust below floor. + Action is blocked. + BLOCK + + diff --git a/website/public/diagrams/execution-receipt.svg b/website/public/diagrams/execution-receipt.svg new file mode 100644 index 0000000..ee651dc --- /dev/null +++ b/website/public/diagrams/execution-receipt.svg @@ -0,0 +1,41 @@ + + + + + + + + + + EXECUTION RECEIPT + + + + VERIFIED + + receipt:rcpt_01J9F4…A2 + + + + + subject agent:invoice-bot + action invoice.write + resource erp://invoices/2026-06 + decision allow + trustScoreAtDecision0.87 + authorityGrantRef grant:9f2a…c41 + attestationRef att:7b3c…e90 + timestamp 2026-06-25T18:40:12Z + + + + + signature ed25519:5d1e…b7f4 + chainHash sha256:c0ffee…a17b + diff --git a/website/public/diagrams/integrations.svg b/website/public/diagrams/integrations.svg new file mode 100644 index 0000000..4a868c3 --- /dev/null +++ b/website/public/diagrams/integrations.svg @@ -0,0 +1,20 @@ + + + + + + + GitHub Actionsenforces at: workflow jobREFERENCE + CI/CD Pipelinesenforces at: pipeline stageREFERENCE + API Gatewaysenforces at: gateway requestEXPERIMENTAL + Service Accountsenforces at: token issuanceEXPERIMENTAL + + Microsoft Copilotenforces at: tool callPLANNED + Azure DevOpsenforces at: release stagePLANNED + LangChainenforces at: agent toolEXPERIMENTAL + CrewAIenforces at: agent stepPLANNED + diff --git a/website/public/diagrams/protocol-loop.svg b/website/public/diagrams/protocol-loop.svg new file mode 100644 index 0000000..8dc2b6d --- /dev/null +++ b/website/public/diagrams/protocol-loop.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + 01Identitynon-human actorasserts itself + 02Attestationsigned evidenceis presented + 03Trust Evalscore vs.threshold + 04Authority Gatechecked beforeexecution + 05Decisionallow · step-up· deny + 06Receiptsigned proofis emitted + + + diff --git a/website/public/diagrams/roadmap.svg b/website/public/diagrams/roadmap.svg new file mode 100644 index 0000000..7dc2367 --- /dev/null +++ b/website/public/diagrams/roadmap.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + PHASE 1 + Spec & Reference + SHIPPED + + + + + PHASE 2 + Runtime Authority + IN PROGRESS + + + + + PHASE 3 + Proofs & Receipts + NEXT + + + + + PHASE 4 + Integrations + PLANNED + + + + + PHASE 5 + Production Hardening + PLANNED + + diff --git a/website/public/diagrams/runtime-authority-flow.svg b/website/public/diagrams/runtime-authority-flow.svg new file mode 100644 index 0000000..870fbc6 --- /dev/null +++ b/website/public/diagrams/runtime-authority-flow.svg @@ -0,0 +1,70 @@ + + + + + + + + + + REQUEST + agent:invoice-bot + invoice.write + + + + + + + + + + Runtime Authority Gate + evaluates before execution + + trust proof + authority grant + decay state + + + + + + + + + + + + allowexecute + + + + step-upre-prove + + + + denyblock + + + + + + + + + + + + RECEIPT + decision: allow + sha256:9f2a…c41 + signed · immutable + + diff --git a/website/public/diagrams/trust-decay-curve.svg b/website/public/diagrams/trust-decay-curve.svg new file mode 100644 index 0000000..f097009 --- /dev/null +++ b/website/public/diagrams/trust-decay-curve.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + 1.0 + 0.0 + time + + + + ACTIVE 0.85–1.00 + DEGRADED 0.65–0.85 + WARNING 0.40–0.65 + CRITICAL 0.00–0.40 + + + + + + + + + + + + + + + attestation + + diff --git a/website/public/diagrams/trust-gap.svg b/website/public/diagrams/trust-gap.svg new file mode 100644 index 0000000..a20a5e0 --- /dev/null +++ b/website/public/diagrams/trust-gap.svg @@ -0,0 +1,49 @@ + + + + + + + + + ESTABLISHED · IDENTITY + + Who is acting? + Authentication proves the actor + is who it claims to be. + + + OAuth · OIDC · SPIFFE + + + + + ESTABLISHED · AUTHORIZATION + + What may it access? + Static grants define scope — + assigned once, rarely revisited. + + + RBAC · SCIM · IAM + + + + + + THE GAP · TTP + + Should this action + execute right now? + Live, evidence-backed trust + gates the action before it runs. + + + TRUST · DECAY · RECEIPTS + + diff --git a/website/public/repo-icon.svg b/website/public/repo-icon.svg new file mode 100644 index 0000000..f17cf30 --- /dev/null +++ b/website/public/repo-icon.svg @@ -0,0 +1,12 @@ + + TTP Protocol icon + Trust lattice nodes connected around a proof core. + + + + + + + + + diff --git a/website/public/social-preview.png b/website/public/social-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..8c101bde1036d772ecc2a13c2f62da2d033d2087 GIT binary patch literal 131109 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 z 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 literal 0 HcmV?d00001 diff --git a/website/public/trust-ring.svg b/website/public/trust-ring.svg new file mode 100644 index 0000000..6364dad --- /dev/null +++ b/website/public/trust-ring.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/public/ttp-hero.svg b/website/public/ttp-hero.svg new file mode 100644 index 0000000..9463ce2 --- /dev/null +++ b/website/public/ttp-hero.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OPEN SOURCE · AGENT TRUST INFRASTRUCTURE + + + PROTOCOL v1.0 + + + Trust Transfer + Protocol + Trust-Before-Execution for AI agents & non-human identities. + + + + $ npm install @blocksifr/ttp-protocol + + + + + + + + + Identitywho is acting + + + + + Trustis it trustworthy right now + + + + + Authorityis this action permitted + + + + + Executiongated runtime action + + + + + Receiptcryptographic proof of the decision + + + + + + + Authority Before Execution·Trust Decay·ZK Proofs·Execution Receipts + From 88ad5d14e645b439717ed2aa4f474e7b78477c7b Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Tue, 15 Sep 2026 08:00:54 -0400 Subject: [PATCH 4/7] Add PCTR: protected consequence trust routing PCTR is the developer entry point to TTP: see what an agent can cause, route it through a trustworthy path, and prove what happened. - Consequence-first mapping: actions classify by the state change they cause, escalated by scale and amount, with the verb deciding over the namespace (payments.status reads; payments.transfer moves money). - Trust graph with the inverse mapping consequence <- action <- tool <- agent <- delegation <- principal. - Consequence Twin (pctr preview), with read-only probes that measure a consequence instead of declaring it; output labels measured vs declared. - TrustRoute Autopilot (pctr route): unauthorized, untrustworthy, stale, consequence-incompatible and policy-invalid routes are removed before any optimization for latency or cost. Rerouting cannot silently expand authority. - Execution authority bound to principal, delegator, session, action, target, material parameters, constraints, policy, consequence, validity and nonce, signed with Ed25519 and verified at the effect boundary. - pctr serve runs that boundary in its own process, holding persistent replay state and the trusted signer list; an unreachable boundary denies. - Signed, chained receipts verifiable with a public key by someone who cannot mint one; unpinned verification reports itself as unpinned. - Agent Time Machine (pctr replay, pctr explain): 16 canonical events with deterministic why derived from the recorded causal chain, plus fork, simulate and compare. - Adapters normalizing openai-agents, claude-agents, langgraph, crewai, autogen, semantic-kernel, mcp and a2a onto those canonical events. - Discovery parses MCP, LangChain, CrewAI and FastMCP tool and agent declarations out of source; declared manifest entries always win. 115 tests, plus two runnable demos. Co-Authored-By: Claude Opus 5 --- .gitignore | 1 + README.md | 54 +++- examples/pctr-consequence-change-demo.mjs | 77 +++++ examples/pctr-universal-fabric-demo.mjs | 88 +++++ package.json | 10 +- packages/pctr/README.md | 372 +++++++++++++++++++++ packages/pctr/bin/pctr.mjs | 376 ++++++++++++++++++++++ packages/pctr/package.json | 12 + packages/pctr/src/adapters.mjs | 173 ++++++++++ packages/pctr/src/authority.mjs | 93 ++++++ packages/pctr/src/boundary.mjs | 91 ++++++ packages/pctr/src/consequences.mjs | 73 +++++ packages/pctr/src/discover.mjs | 180 +++++++++++ packages/pctr/src/events.mjs | 10 + packages/pctr/src/graph.mjs | 116 +++++++ packages/pctr/src/index.mjs | 17 + packages/pctr/src/keys.mjs | 78 +++++ packages/pctr/src/observe.mjs | 45 +++ packages/pctr/src/probe.mjs | 69 ++++ packages/pctr/src/protect.mjs | 136 ++++++++ packages/pctr/src/receipt.mjs | 74 +++++ packages/pctr/src/render.mjs | 141 ++++++++ packages/pctr/src/router.mjs | 108 +++++++ packages/pctr/src/store.mjs | 49 +++ packages/pctr/src/timeline.mjs | 135 ++++++++ packages/pctr/src/trust.mjs | 40 +++ packages/pctr/src/ttp.mjs | 3 + packages/pctr/src/twin.mjs | 65 ++++ packages/pctr/tests/adapters.test.mjs | 74 +++++ packages/pctr/tests/boundary.test.mjs | 89 +++++ packages/pctr/tests/discover.test.mjs | 102 ++++++ packages/pctr/tests/pctr.test.mjs | 268 +++++++++++++++ 32 files changed, 3214 insertions(+), 5 deletions(-) create mode 100644 examples/pctr-consequence-change-demo.mjs create mode 100644 examples/pctr-universal-fabric-demo.mjs create mode 100644 packages/pctr/README.md create mode 100755 packages/pctr/bin/pctr.mjs create mode 100644 packages/pctr/package.json create mode 100644 packages/pctr/src/adapters.mjs create mode 100644 packages/pctr/src/authority.mjs create mode 100644 packages/pctr/src/boundary.mjs create mode 100644 packages/pctr/src/consequences.mjs create mode 100644 packages/pctr/src/discover.mjs create mode 100644 packages/pctr/src/events.mjs create mode 100644 packages/pctr/src/graph.mjs create mode 100644 packages/pctr/src/index.mjs create mode 100644 packages/pctr/src/keys.mjs create mode 100644 packages/pctr/src/observe.mjs create mode 100644 packages/pctr/src/probe.mjs create mode 100644 packages/pctr/src/protect.mjs create mode 100644 packages/pctr/src/receipt.mjs create mode 100644 packages/pctr/src/render.mjs create mode 100644 packages/pctr/src/router.mjs create mode 100644 packages/pctr/src/store.mjs create mode 100644 packages/pctr/src/timeline.mjs create mode 100644 packages/pctr/src/trust.mjs create mode 100644 packages/pctr/src/ttp.mjs create mode 100644 packages/pctr/src/twin.mjs create mode 100644 packages/pctr/tests/adapters.test.mjs create mode 100644 packages/pctr/tests/boundary.test.mjs create mode 100644 packages/pctr/tests/discover.test.mjs create mode 100644 packages/pctr/tests/pctr.test.mjs diff --git a/.gitignore b/.gitignore index 594dda0..35b4526 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ __pycache__/ .venv/ *.log .DS_Store +.pctr/ diff --git a/README.md b/README.md index cbe8890..48eca07 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,12 @@

    - The protocol layer for agent trust.
    - Every action must earn authority before execution. Every decision must be provable after. + See what your agents can cause. Route them safely. Prove what happened.
    + Open-source trust and execution infrastructure for AI agents.

    + Start with PCTR  ·  Read the Spec  ·  Quickstart  ·  Examples  ·  @@ -36,6 +37,55 @@ OAuth standardized delegated access. SCIM standardized identity provisioning. ** Identity, Attestation, Trust Evaluation, Runtime Authority Gate, Decision, Execution Receipt

    +Your agent can have valid credentials and still be about to do the wrong thing. + +``` +Objective -> Trust Route -> Consequence Preview -> Execution Authority -> Protected Action -> Receipt +``` + +## Start Here: PCTR + +**[PCTR](packages/pctr/)** — Protected Consequence Trust Routing — is the developer entry point. It answers three questions, in this order: + +| | Question | Command | +| --- | --- | --- | +| **1. Consequence** | What can this action cause? | `pctr preview ` | +| **2. Route** | Which trustworthy agent path may get there? | `pctr route ` | +| **3. Authority** | Is this exact execution allowed right now? | `pctr protect ` | + +```bash +npm run pctr -- init # discover agents and tools, write pctr.json +npm run pctr -- scan # what consequences can they reach? +``` + +``` +Agents found 5 +Tools found 3 +Potential actions 4 + +Protected consequences + +CRITICAL 1 +HIGH 1 +MEDIUM 1 + +Highest priority: + +customers.delete + +Problem: + +The final action can cause "data deleted" irreversibly without independent execution authority. + +Recommended: + +Add TTP authority verification before customers.delete. +``` + +No account, no network: everything stays in `./pctr.json` and `./.pctr`. PCTR is not published to npm yet — run it from a clone, or `npm link ./packages/pctr` for the bare `pctr` command. Three flagship capabilities sit on top of that graph — the **Consequence Twin** (`pctr preview`), **TrustRoute Autopilot** (`pctr route`), and the **Agent Time Machine** (`pctr replay`, `pctr explain`) — with Ed25519-signed receipts, read-only probes that measure a consequence instead of declaring it, adapters for the common agent frameworks, and an effect boundary (`pctr serve`) that verifies authority in its own process. See the [PCTR README](packages/pctr/README.md), `npm run demo:pctr` and `npm run demo:pctr-fabric`. + +PCTR routes to the consequence. TTP binds the authority for the exact execution that reaches it. + ## Why TTP Exists Software is moving from advising to acting. Agents call tools, copilots trigger workflows, pipelines modify production, service accounts move data. The old model — `authenticate → authorize → execute → log` — never asks the question that matters at runtime: diff --git a/examples/pctr-consequence-change-demo.mjs b/examples/pctr-consequence-change-demo.mjs new file mode 100644 index 0000000..7e56098 --- /dev/null +++ b/examples/pctr-consequence-change-demo.mjs @@ -0,0 +1,77 @@ +#!/usr/bin/env node +// PCTR end-to-end: a transfer changes mid-run, the consequence changes with it, +// the route it was riding on becomes inadmissible, and authority is re-established +// on the new terms. Run: node examples/pctr-consequence-change-demo.mjs +import { + buildGraph, previewConsequence, consequenceChanged, resolveRoute, reroute, + protect, createTimeline, replay, why, verifyReceipt +} from '../packages/pctr/src/index.mjs'; + +const graph = buildGraph({ + principal: 'user:ops', + agents: [ + { id: 'planner', framework: 'openai-agents', trust: 0.98, evidenceAgeSeconds: 15, authority: ['*'], jurisdiction: 'eu', latencyMs: 60, tools: [], delegatesTo: ['finance-agent-a', 'finance-agent-d'] }, + { id: 'finance-agent-a', framework: 'langgraph', trust: 0.96, evidenceAgeSeconds: 240, authority: ['payments.*'], jurisdiction: 'eu', latencyMs: 40, tools: ['payments'] }, + { id: 'finance-agent-d', framework: 'claude-agents', trust: 0.97, evidenceAgeSeconds: 20, authority: ['payments.*'], jurisdiction: 'eu', latencyMs: 130, tools: ['payments'] } + ], + tools: [{ id: 'payments', protocol: 'mcp', actions: ['payments.transfer'] }], + actions: [{ id: 'payments.transfer', amount: 1800, connectedWorkflows: 2 }], + policy: { requireApprovalAtOrAbove: 'CRITICAL', approvalThresholds: { amount: 5000 }, decayPerHop: 0.05 } +}); + +const timeline = createTimeline({ objective: 'Pay invoice INV-4471' }); +const line = (s = '') => console.log(s); + +// 1. The objective arrives and the first amount is proposed. +const started = timeline.record('AGENT_STARTED', { objective: 'Pay invoice INV-4471' }, { subject: 'planner' }); +const first = timeline.record('ACTION_PROPOSED', { action: 'payments.transfer', amount: 1800 }, { subject: 'planner', because: [started.id] }); + +const before = previewConsequence(graph, 'payments.transfer', { amount: 1800 }); +timeline.record('CONSEQUENCE_DETECTED', { consequence: before.consequence, severity: before.severity }, { because: [first.id] }); +const routeBefore = resolveRoute(graph, 'payments.transfer', { severity: before.severity }); +const selectedBefore = timeline.record('ROUTE_SELECTED', { routeId: routeBefore.selected.routeId }, { because: [first.id] }); + +line(`Proposed transfer: $1,800 -> ${before.severity}`); +line(`Route: ${routeBefore.selected.routeId}`); + +// 2. The amount changes. The consequence changes with it. +const changed = timeline.record('ACTION_PROPOSED', { action: 'payments.transfer', amount: 18000 }, { subject: 'planner', because: [first.id] }); +const after = previewConsequence(graph, 'payments.transfer', { amount: 18000 }); +const detected = timeline.record('CONSEQUENCE_DETECTED', + { consequence: after.consequence, severity: after.severity, reason: `Transfer increased from $1,800 to $18,000, so the consequence is now ${after.severity}.` }, + { because: [changed.id] }); + +line(); +line(`Amount changed: $1,800 -> $18,000 (consequence changed: ${consequenceChanged(before, after)})`); + +// 3. The route it was riding on is no longer admissible for the new consequence. +timeline.record('ROUTE_INVALIDATED', + { routeId: routeBefore.selected.routeId, reason: 'The consequence changed, so the route selected for the smaller transfer is no longer admissible.', policy: 'local-v1' }, + { because: [detected.id, selectedBefore.id] }); + +// Rerouting may never admit a route on weaker grounds than the one it replaces. +const attemptedDowngrade = reroute(graph, 'payments.transfer', { ...routeBefore, severity: 'CRITICAL', trustRequired: 0.9 }, { severity: 'MEDIUM' }); +line(`Attempted cheaper route at lower severity: ${attemptedDowngrade.expansionBlocked ? 'BLOCKED (authority may not silently expand)' : 'allowed'}`); + +// 4. Run the protected loop at the new consequence — first without approval. +const denied = await protect(graph, { action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 }, agent: 'planner' }, { timeline }); +line(); +line(`Without approval: ${denied.receipt.verifier.decision} — ${denied.receipt.verifier.failures[0].message}`); + +// 5. Approval is recorded, and authority is bound to this exact execution. +const allowed = await protect(graph, + { action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 }, agent: 'planner' }, + { timeline, approval: { by: 'ops-oncall', at: new Date().toISOString() }, execute: () => ({ transferId: 'tr_88213' }) }); + +line(`With approval: ${allowed.receipt.verifier.decision} — executed ${allowed.result.status}`); +line(`Receipt ${allowed.receipt.receiptId} verifies: ${verifyReceipt(allowed.receipt).valid}`); + +line(); +line('TIMELINE'); +for (const e of replay(timeline)) line(` ${e.at.slice(11, 19)} ${e.line}`); + +const answer = why(timeline, 'ROUTE_INVALIDATED'); +line(); +line(answer.question); +line(` ${answer.answer}`); +for (const b of answer.because) line(` - ${b}`); diff --git a/examples/pctr-universal-fabric-demo.mjs b/examples/pctr-universal-fabric-demo.mjs new file mode 100644 index 0000000..858157b --- /dev/null +++ b/examples/pctr-universal-fabric-demo.mjs @@ -0,0 +1,88 @@ +#!/usr/bin/env node +// Four frameworks, one security meaning, one effect boundary. +// Each agent below emits its own native event shape. PCTR normalizes them into the +// canonical events, classifies the consequence, routes to a trustworthy agent, and has +// the authority verified by a boundary running in its own process. +// Run: node examples/pctr-universal-fabric-demo.mjs +import { + buildGraph, createTimeline, ingest, replay, protect, why, + startBoundaryServer, remoteBoundary, createBoundary, generateKeyPair, exportPublic, verifyReceipt +} from '../packages/pctr/src/index.mjs'; + +const line = (s = '') => console.log(s); + +const graph = buildGraph({ + principal: 'user:ops', + agents: [ + { id: 'planner', framework: 'openai-agents', trust: 0.98, evidenceAgeSeconds: 15, authority: ['*'], latencyMs: 60, tools: [], delegatesTo: ['research', 'finance'] }, + { id: 'research', framework: 'langgraph', trust: 0.9, evidenceAgeSeconds: 40, authority: ['reports.*'], latencyMs: 30, tools: ['reports'] }, + { id: 'finance', framework: 'crewai', trust: 0.97, evidenceAgeSeconds: 25, authority: ['payments.*'], latencyMs: 110, tools: ['payments'] } + ], + tools: [ + { id: 'reports', protocol: 'mcp', actions: ['reports.read'] }, + { id: 'payments', protocol: 'mcp', actions: ['payments.transfer'] } + ], + actions: [{ id: 'payments.transfer', amount: 1800, connectedWorkflows: 2 }], + policy: { requireApprovalAtOrAbove: 'CRITICAL', approvalThresholds: { amount: 5000 } } +}); + +const timeline = createTimeline({ objective: 'Settle supplier invoice INV-4471' }); + +// Each framework hands PCTR the events it already emits. Nothing is rewritten to suit us. +ingest('openai-agents', [ + { type: 'agent_start', agent: 'planner', input: 'Settle supplier invoice INV-4471' }, + { type: 'token_usage', tokens: 1420 }, + { type: 'handoff', from_agent: 'planner', to_agent: 'research' } +], timeline); + +ingest('langgraph', [ + { event: 'on_tool_start', name: 'reports.read', data: { input: { supplier: 'acme' } } }, + { event: 'on_llm_new_token', data: { chunk: 'The' } }, + { event: 'on_tool_end', name: 'reports.read' } +], timeline); + +ingest('mcp', [ + { method: 'tools/list', server: 'payments', result: { tools: [{ name: 'payments.transfer' }, { name: 'payments.status' }] } } +], timeline); + +ingest('crewai', [ + { type: 'agent_delegated', from_agent: 'planner', to_agent: 'finance' }, + { type: 'tool_usage_started', tool: 'payments.transfer', tool_args: { amount: 18000 }, agent: 'finance' } +], timeline); + +line('NORMALIZED FROM FOUR FRAMEWORKS'); +for (const e of replay(timeline)) line(` ${e.line}`); + +// The boundary holds the key list and the replay state, in its own process. +const key = generateKeyPair(); +const boundary = createBoundary({ trustedKeyIds: [key.keyId], publicKey: exportPublic(key.publicKey) }); +const { url, close } = await startBoundaryServer({ port: 0, boundary }); + +line(); +line(`Effect boundary running at ${url}, trusting only ${key.keyId}`); + +const request = { action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 }, agent: 'finance' }; +const options = { timeline, boundary: remoteBoundary(url), keyPair: key }; + +const denied = await protect(graph, request, options); +line(`Without approval: ${denied.receipt.verifier.decision} — ${denied.receipt.verifier.failures[0].message}`); + +const allowed = await protect(graph, request, { + ...options, approval: { by: 'ops-oncall' }, execute: () => ({ transferId: 'tr_88213' }) +}); +line(`With approval: ${allowed.receipt.verifier.decision} at ${allowed.receipt.verifier.boundary}`); +line(`Receipt verifies against the boundary's public key: ${verifyReceipt(allowed.receipt, { publicKey: exportPublic(key.publicKey) }).valid}`); + +// Replaying the same authority is refused: it has already been spent. +const replayed = await remoteBoundary(url).verify(allowed.authority, { + action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 }, principal: 'user:ops' +}); +line(`Replaying that authority: ${replayed.decision} (${replayed.failures.map((f) => f.code).join(', ')})`); + +const answer = why(timeline, 'EXECUTION_DENIED'); +line(); +line(answer.question); +line(` ${answer.answer}`); +for (const b of answer.because.slice(-4)) line(` - ${b}`); + +await close(); diff --git a/package.json b/package.json index 966f7bf..3a31dcf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@blocksifr/ttp-protocol", "version": "0.1.0", - "description": "Trust Transfer Protocol — open trustworthiness primitives for autonomous systems, non-human identities, and runtime authority.", + "description": "Trust Transfer Protocol \u2014 open trustworthiness primitives for autonomous systems, non-human identities, and runtime authority.", "private": false, "type": "module", "publishConfig": { @@ -38,13 +38,17 @@ "ttp": "node src/index.js", "build:sdk": "npm install --prefix sdk/typescript && npm run build --prefix sdk/typescript", "build:trust-authority": "npm install --prefix reference-implementations/trust-authority && npm run build --prefix reference-implementations/trust-authority", - "test": "node --test tests/*.test.mjs packages/trust-routing-engine/tests/*.test.mjs", + "test": "node --test tests/*.test.mjs packages/trust-routing-engine/tests/*.test.mjs packages/pctr/tests/*.test.mjs", "test:ttp": "node --test tests/*.test.mjs", "test:trust-routing": "node --test packages/trust-routing-engine/tests/*.test.mjs", "check:examples": "node src/index.js check examples/01-basic-agent.ttp && node src/index.js check examples/02-trust-decay.ttp && node src/index.js check examples/03-threshold-proof.ttp && node src/index.js check examples/04-delegated-trust.ttp && node src/index.js check examples/05-agent-tool-trust-wrapper.ttp && node src/index.js check examples/06-cicd-pipeline-trust-proof.ttp && node src/index.js check examples/07-api-client-trust-proof.ttp && node src/index.js check examples/08-msp-mssp-trust-proof.ttp", "assets:fonts": "python3 assets/brand/embed-fonts.py", "assets:social": "node assets/brand/render-png.mjs assets/social-preview.svg assets/social-preview.png 1280", - "assets": "npm run assets:fonts && npm run assets:social" + "assets": "npm run assets:fonts && npm run assets:social", + "test:pctr": "node --test packages/pctr/tests/*.test.mjs", + "pctr": "node packages/pctr/bin/pctr.mjs", + "demo:pctr": "node examples/pctr-consequence-change-demo.mjs", + "demo:pctr-fabric": "node examples/pctr-universal-fabric-demo.mjs" }, "devDependencies": { "@fontsource/inter": "^5.2.8", diff --git a/packages/pctr/README.md b/packages/pctr/README.md new file mode 100644 index 0000000..30847c5 --- /dev/null +++ b/packages/pctr/README.md @@ -0,0 +1,372 @@ +# PCTR — Protected Consequence Trust Routing + +**See what your agents can cause. Route them safely. Prove what happened.** + +Your agent can have valid credentials and still be about to do the wrong thing. + +``` +Objective -> Trust Route -> Consequence Preview -> Execution Authority -> Protected Action -> Receipt +``` + +## 60 seconds + +Not published to npm yet. From a clone of this repo: + +```bash +npm run pctr -- init # discover agents and tools, write pctr.json +npm run pctr -- scan # what consequences can they reach? +``` + +Or link it to get the bare `pctr` command: `npm link ./packages/pctr`. + +``` +PCTR + +Scanning your agents... + +Agents found 5 +Tools found 3 +External systems 3 +Potential actions 4 + +Protected consequences + +CRITICAL 1 +HIGH 1 +MEDIUM 1 + +Highest priority: + +customers.delete + +Route: + +user:local + | + v +support-agent + | + v +admin-agent + | + v +database + | + v +customers.delete + +Problem: + +The final action can cause "data deleted" irreversibly without independent execution authority. + +Recommended: + +Add TTP authority verification before customers.delete. +``` + +No account. No network. Everything stays in `./pctr.json` and `./.pctr`. + +## The three questions + +| Question | Command | Answers | +| --- | --- | --- | +| **Consequence** — what can this action cause? | `pctr preview ` | records, money, reversibility, blast radius | +| **Route** — which trustworthy agent path may get there? | `pctr route ` | the selected path, and why every other one was rejected | +| **Authority** — is this exact execution allowed right now? | `pctr protect ` | an allow/deny decision plus a verifiable receipt | + +## Consequence Twin + +See what your AI is about to change before it changes it — `git diff` for autonomous +agents. It reasons over the graph and the parameters you declare; it does not query your +live systems (see [Honest limits](#honest-limits)). + +```bash +pctr preview customers.delete --records 1842 +``` + +``` +CONSEQUENCE PREVIEW + +Action customers.delete +Causes data deleted +Records affected 1842 +Reversible NO +Connected workflows 4 +Blast radius WIDE (100/100) +Routes that reach it 1 +Risk CRITICAL + +Recommended + +- Require TTP execution authority bound to these exact parameters +- Limit batch to 25 records (currently 1842) + require approval +- Notify 4 connected workflows before executing +- Verify authority at the effect boundary, not in the calling agent +``` + +## TrustRoute Autopilot + +The right trustworthy agent gets the job automatically. Admissibility is decided first; +only routes that survive are optimized for latency and cost. A security constraint is +never traded away for a faster or cheaper route. + +```bash +pctr route payments.transfer --amount 18000 +``` + +``` +ROUTE SELECTED + +user:local + | + v +planner + | + v +finance-agent-d + | + v +payments + | + v +payments.transfer + +Effective trust 0.9178 (0.9 required for CRITICAL) +Hops 5 +Human approval REQUIRED + +Rejected routes + +user:local -> planner -> finance-agent-a -> payments -> payments.transfer + x finance-agent-a evidence is 4200s old; CRITICAL actions require evidence under 300s + x effective trust 0.6579 is below the 0.9 required for CRITICAL consequences +``` + +At $1,800 the same action is `HIGH` and needs no approval; the amount is what moves it to +`CRITICAL`. Material parameters change the consequence, and the consequence sets the bar. + +`finance-agent-a` was the *faster* route. It was still rejected. + +## Agent Time Machine + +Replay exactly why your AI did what it did. + +```bash +pctr protect payments.transfer --amount 18000 +pctr replay +pctr explain EXECUTION_DENIED +``` + +``` +WHY WAS THIS EXECUTION DENIED? + +policy requires human approval for CRITICAL consequences + +Because + +- Objective received: protect payments.transfer +- Action proposed: payments.transfer ($18000) +- Consequence detected: MONEY_MOVED (CRITICAL) +- Route selected: user:local -> planner -> finance-agent-d -> payments -> payments.transfer +``` + +Every answer is derived from the recorded causal chain, not re-narrated by a model. +Runs can also be forked and compared: + +```bash +pctr replay --fork e3 +pctr replay --compare +``` + +## Execution authority + +A valid identity is not enough. A valid credential is not enough. A valid route is not +enough. Authority binds principal, delegator, session, action, target, material +parameters, constraints, policy, consequence, validity window and nonce — and the effect +boundary verifies it independently of the agent that asked. + +```js +import { issueAuthority, verifyAuthority } from '@blocksifr/pctr'; + +const authority = issueAuthority({ + principal: 'user:ops', action: 'payments.transfer', target: 'acct:9931', + params: { amount: 1800 }, consequence: 'MONEY_MOVED', route +}); + +// Same authority, changed amount — possession is not authority. +verifyAuthority(authority, { action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 } }); +// -> { allowed: false, failures: [{ code: 'PARAMETER_MISMATCH', ... }] } +``` + +Authority also expires and can only be spent once (`REPLAYED_AUTHORITY`). + +## Receipts + +Every protected execution produces verifiable evidence of what was +requested, who delegated it, which route was selected, what consequence was identified, +what parameters were bound, which verifier checked it, and what actually executed. + +```bash +pctr receipt # show the last one +pctr verify # verify all of them, including the chain +``` + +A receipt that records an execution which was never allowed fails verification +(`EXECUTED_WITHOUT_AUTHORITY`), and a removed or reordered receipt breaks the chain. + +Receipts and authority are signed with **Ed25519**. Verification takes the public key, so +someone who can check your receipts cannot mint one: + +```bash +pctr keys --export public-key.pem # share this; never share .pctr/keys/signing-key.pem +pctr verify --key public-key.pem +``` + +``` +RECEIPT VERIFICATION + +Receipts checked 3 +Valid 2 of 3 +Chain BROKEN +Signer verified against a pinned key + x rcpt-3d80fffd-b45a-405f-8a70-007b5ce7bfde + receipt signature does not verify +``` + +Verifying without a pinned key still works, but reports itself as `signerVerified: false` +with an `UNPINNED_KEY` warning — internal consistency is not proof of who signed. Pin +signers permanently with `"trustedSigners": ["ed25519:…"]` in `pctr.json`. + +## Commands + +``` +pctr init Discover agents and tools, write pctr.json +pctr scan What consequences can your agents reach? +pctr graph Show the trust graph +pctr preview Consequence Twin +pctr route TrustRoute Autopilot +pctr protect Run the full loop and issue a receipt +pctr simulate Same, without executing any effect +pctr replay [run] Agent Time Machine +pctr explain Why was this allowed, denied, or rerouted? +pctr receipt [id] Show an execution receipt +pctr verify [id] Verify receipt signatures and the receipt chain +pctr keys Show your signing key id and public key +pctr serve Run the effect boundary as its own process +pctr doctor Check your setup +``` + +Every command prints plain English first. Add `--json` for machine-readable output. + +## pctr.json + +```json +{ + "principal": "user:ops", + "agents": [ + { "id": "planner", "framework": "openai-agents", "trust": 0.98, "evidenceAgeSeconds": 20, + "authority": ["*"], "jurisdiction": "eu", "tools": [], "delegatesTo": ["finance-agent-d"] }, + { "id": "finance-agent-d", "framework": "claude-agents", "trust": 0.97, "evidenceAgeSeconds": 30, + "authority": ["payments.*"], "jurisdiction": "eu", "latencyMs": 140, "tools": ["payments"] } + ], + "tools": [{ "id": "payments", "protocol": "mcp", "actions": ["payments.transfer"] }], + "actions": [{ "id": "payments.transfer", "amount": 1800, "connectedWorkflows": 2 }], + "policy": { + "requireApprovalAtOrAbove": "CRITICAL", + "approvalThresholds": { "amount": 5000 }, + "jurisdictions": { "MONEY_MOVED": ["eu"] }, + "maxHops": 6, + "decayPerHop": 0.05 + } +} +``` + +Agents are participants, not platforms. A new framework needs an adapter that maps its +runtime events onto the canonical PCTR events — not a redesign of PCTR. + +## Universal agent fabric + +Adapters ship for `openai-agents`, `claude-agents`, `langgraph`, `crewai`, `autogen`, +`semantic-kernel`, `mcp`, `a2a`, and a `generic` envelope for everything else. Each one +maps a framework's own events onto the 16 canonical security events and drops the rest: + +```js +import { ingest, createTimeline } from '@blocksifr/pctr'; + +const timeline = createTimeline({ objective: 'Settle invoice INV-4471' }); +ingest('crewai', crewEvents, timeline); +ingest('langgraph', graphEvents, timeline); // one timeline, one security meaning +``` + +A tool call in any of them becomes `ACTION_PROPOSED` plus the `CONSEQUENCE_DETECTED` it +implies — the part every framework leaves out. Token usage, streamed text and other +framework internals are dropped rather than invented into events. + +See `node examples/pctr-universal-fabric-demo.mjs` for four frameworks feeding one +protected execution through a remote effect boundary. + +## Relationship to TTP + +PCTR answers *which path through multiple agents is trustworthy enough to reach this +consequence*. [TTP](../../README.md) answers *is this exact execution authority valid +for this principal, action, target, parameters, delegation and moment*. + +> TLS protects the channel. TTP protects the authority transferred through the channel. + +## Probes: measure the consequence, don't declare it + +A number typed into `pctr.json` is a guess. A probe measures. Probes must be read-only — +a `COUNT`, a dry run, a `terraform plan` — because PCTR runs them *before* anything is +authorized. + +```js +// probes/count-customers.mjs +export default async function probe({ action, params }) { + const { rows } = await db.query('select count(*) as rows from customers where inactive_days > $1', [params.olderThanDays]); + return { recordsAffected: Number(rows), connectedWorkflows: 4, reversible: false }; +} +``` + +```json +{ "probes": { "customers.delete": "./probes/count-customers.mjs" } } +``` + +``` +Records affected 1842 (measured) +``` + +A shell probe works too (`{ "command": "./plan.sh" }`, JSON on stdout, with `PCTR_ACTION`, +`PCTR_TARGET` and `PCTR_PARAMS` in the environment). If a probe fails, the preview falls +back to declared values and says so — it never silently becomes "no consequence". + +## The effect boundary + +The requesting agent must not enforce its own authority, so run the boundary somewhere +the agent does not control: + +```bash +pctr serve --port 8787 # holds the replay state and the trusted signers +pctr protect payments.transfer --boundary http://127.0.0.1:8787 +``` + +Spent nonces persist to `.pctr/spent-nonces.json`, so an authority cannot be replayed +across a restart. If the boundary is unreachable, execution is **denied** — it never +fails open. + +## Honest limits + +- **Blast radius is a heuristic**, not a measurement: severity, record count, connected + workflows and route count folded into a 0-100 score. The inputs are measurable; the + weighting is a judgement call. +- **Trust scores come from your manifest.** PCTR decays them, tests them against the bar + the consequence sets, and refuses stale evidence — but it does not attest agents + itself. Wire `trust` and `evidenceAgeSeconds` to a real attestation source. +- **Discovery reads source, not running systems.** It parses MCP/LangChain/CrewAI tool + and agent declarations statically, and does not connect to a live MCP server to list + its tools. Anything it cannot see, you declare — and declared entries always win. +- **Keys live on disk.** `.pctr/keys/signing-key.pem` is written 0600 and must not be + committed. KMS/HSM custody is commercial BlockSiFr, not this package. +- **`pctr serve` is plain HTTP on localhost.** Put it behind TLS and your own + authentication before it leaves the machine. + +Apache-2.0. diff --git a/packages/pctr/bin/pctr.mjs b/packages/pctr/bin/pctr.mjs new file mode 100755 index 0000000..69f3ddb --- /dev/null +++ b/packages/pctr/bin/pctr.mjs @@ -0,0 +1,376 @@ +#!/usr/bin/env node +import { buildGraph, summarize, protectedActions } from '../src/graph.mjs'; +import { discover, defaultPolicy } from '../src/discover.mjs'; +import { previewConsequence } from '../src/twin.mjs'; +import { previewMeasured } from '../src/probe.mjs'; +import { resolveRoute } from '../src/router.mjs'; +import { protect, simulate } from '../src/protect.mjs'; +import { createBoundary, startBoundaryServer, remoteBoundary, persistentReplayStore } from '../src/boundary.mjs'; +import { verifyReceipt, verifyReceiptChain } from '../src/receipt.mjs'; +import { createTimeline, fromJSON, why, compare, fork } from '../src/timeline.mjs'; +import { defaultKeyPair, exportPublic } from '../src/keys.mjs'; +import fs from 'node:fs'; +import path from 'node:path'; +import * as store from '../src/store.mjs'; +import * as r from '../src/render.mjs'; + +const VERSION = '0.1.0'; + +const argv = process.argv.slice(2); +const command = argv[0]; +// Flags that take a value, so their value is never mistaken for a positional argument. +const VALUE_FLAGS = new Set(['amount', 'records', 'recordsAffected', 'batch', 'params', 'approve', + 'target', 'agent', 'objective', 'compare', 'fork', 'key', 'export', 'run', 'probe', 'boundary', 'port']); +const positional = (() => { + const out = []; + for (let i = 1; i < argv.length; i++) { + const token = argv[i]; + if (token.startsWith('--')) { + if (VALUE_FLAGS.has(token.slice(2)) && argv[i + 1] && !argv[i + 1].startsWith('--')) i++; + continue; + } + out.push(token); + } + return out; +})(); +const flag = (name, fallback = null) => { + const i = argv.indexOf(`--${name}`); + if (i === -1) return fallback; + const next = argv[i + 1]; + return next && !next.startsWith('--') ? next : true; +}; +const asJson = argv.includes('--json'); +const out = (human, data) => console.log(asJson ? JSON.stringify(data, null, 2) : human); + +const params = () => { + const p = {}; + for (const key of ['amount', 'records', 'recordsAffected', 'batch']) { + const v = flag(key); + if (v != null && v !== true) p[key === 'records' ? 'recordsAffected' : key] = Number(v); + } + const raw = flag('params'); + if (raw && raw !== true) Object.assign(p, JSON.parse(raw)); + return p; +}; + +// How receipts get checked: an explicit public key file is real third-party +// verification; trustedSigners in pctr.json pins who is allowed to have signed. +function verifyOptions() { + const keyPath = flag('key'); + const manifest = store.readManifest(); + return { + publicKey: keyPath && keyPath !== true ? fs.readFileSync(String(keyPath), 'utf8') : undefined, + trustedKeyIds: manifest?.trustedSigners + }; +} + +function loadGraph() { + const manifest = store.readManifest(); + if (!manifest) { + console.error('No pctr.json found. Run: pctr init'); + process.exit(2); + } + return buildGraph(manifest); +} + +async function main() { + switch (command) { + case undefined: + case 'help': case '--help': case '-h': + console.log(help()); return 0; + case 'version': case '--version': case '-v': + console.log(`pctr ${VERSION}`); return 0; + + case 'init': { + const existing = store.readManifest(); + const { manifest, notes, discovered } = discover(process.cwd(), { declared: existing }); + if (!manifest.agents.length) { + manifest.agents = exampleManifest().agents; + manifest.tools = exampleManifest().tools; + manifest.actions = exampleManifest().actions; + notes.push('No agents detected; wrote a worked example you can edit.'); + } + const path = store.writeManifest(manifest); + if (asJson) return out(null, { path, manifest, notes }); + console.log(r.heading('pctr initialized')); + console.log(`Wrote ${path}`); + console.log(r.field('Agents', String(discovered.agents || manifest.agents.length))); + console.log(r.field('Tools', String(discovered.tools || manifest.tools.length))); + for (const n of notes) console.log(r.dim(`- ${n}`)); + console.log(`\nNext: ${r.bold('pctr scan')}`); + return 0; + } + + case 'scan': { + const graph = loadGraph(); + return out(r.renderScan(graph), { summary: summarize(graph), protected: protectedActions(graph) }); + } + + case 'graph': { + const graph = loadGraph(); + return out(r.renderGraph(graph), { + principal: graph.principal, + nodes: [...graph.nodes.values()], + edges: graph.edges + }); + } + + case 'preview': { + const graph = loadGraph(); + const action = positional[0] ?? protectedActions(graph)[0]?.id; + if (!action) return fail('Nothing to preview. Pass an action: pctr preview '); + const probes = flag('probe') && flag('probe') !== true ? { [action]: String(flag('probe')) } : undefined; + const p = await previewMeasured(graph, action, params(), { probes, target: flag('target') }); + return out(r.renderPreview(p), p); + } + + case 'route': { + const graph = loadGraph(); + const action = positional[0] ?? protectedActions(graph)[0]?.id; + if (!action) return fail('Pass an action: pctr route '); + // Material parameters can change the consequence, and the consequence sets the bar. + const severity = previewConsequence(graph, action, params()).severity; + const result = resolveRoute(graph, action, { target: flag('target'), severity }); + return out(r.renderRoute(result), result); + } + + case 'protect': case 'simulate': { + const graph = loadGraph(); + const action = positional[0] ?? protectedActions(graph)[0]?.id; + if (!action) return fail(`Pass an action: pctr ${command} `); + const request = { action, target: flag('target') ?? action, params: params(), agent: flag('agent') }; + const probes = flag('probe') && flag('probe') !== true ? { [action]: String(flag('probe')) } : undefined; + const measured = await previewMeasured(graph, action, request.params, { probes, target: request.target }); + const approval = flag('approve') ? { by: String(flag('approve')), at: new Date().toISOString() } : null; + const run = await (command === 'simulate' ? simulate : protect)(graph, request, { + objective: flag('objective') ?? `${command} ${action}`, + approval, + preview: measured, + boundary: flag('boundary') && flag('boundary') !== true ? remoteBoundary(String(flag('boundary'))) : undefined, + priorReceiptHash: store.listReceipts().at(-1)?.receiptHash ?? null, + timeline: createTimeline({ objective: flag('objective') ?? `${command} ${action}` }) + }); + store.saveRun(run.timeline); + store.saveReceipt(run.receipt); + if (asJson) return out(null, { allowed: run.allowed, preview: run.preview, route: run.route, receipt: run.receipt, timeline: run.timeline.toJSON() }); + console.log(r.renderPreview(run.preview)); + if (run.routeResult) console.log(r.renderRoute(run.routeResult)); + console.log(r.renderReceipt(run.receipt, verifyReceipt(run.receipt))); + console.log(`\n${r.dim(`Replay this run: pctr replay ${run.timeline.runId}`)}`); + return run.allowed ? 0 : 1; + } + + case 'replay': { + const data = store.loadRun(positional[0]); + if (!data) return fail('No runs recorded yet. Run: pctr protect '); + const timeline = fromJSON(data); + if (flag('compare') && flag('compare') !== true) { + const other = store.loadRun(String(flag('compare'))); + if (!other) return fail(`No run named ${flag('compare')}`); + const diff = compare(timeline, fromJSON(other)); + return out(renderCompare(diff, data.runId, other.runId), diff); + } + if (flag('fork')) { + const forked = fork(timeline, { upTo: flag('fork') !== true ? String(flag('fork')) : null }); + store.saveRun(forked); + return out(`${r.renderTimeline(forked)}\n${r.dim(`Forked run saved as ${forked.runId}`)}`, forked.toJSON()); + } + return out(r.renderTimeline(timeline), data); + } + + case 'explain': { + const data = store.loadRun(flag('run') !== true ? flag('run') : null); + if (!data) return fail('No runs recorded yet. Run: pctr protect '); + const question = positional[0] ?? 'EXECUTION_DENIED'; + const answer = why(fromJSON(data), question); + return out(r.renderWhy(answer), answer); + } + + case 'serve': { + // The boundary runs here, in its own process, holding the replay state and the + // list of signers it accepts. Agents ask it; they do not decide for themselves. + const manifest = store.readManifest(); + const keyPath = flag('key'); + const boundary = createBoundary({ + trustedKeyIds: manifest?.trustedSigners, + publicKey: keyPath && keyPath !== true ? fs.readFileSync(String(keyPath), 'utf8') : undefined, + replayStore: persistentReplayStore(path.join(store.dir(), 'spent-nonces.json')) + }); + const port = Number(flag('port') !== true && flag('port') != null ? flag('port') : 8787); + const { url } = await startBoundaryServer({ port, boundary, + onDecision: (decision, { execution }) => { + console.log(`${decision.allowed ? r.green('ALLOW') : r.red('DENY ')} ${execution.action} -> ${execution.target ?? ''} ${decision.allowed ? '' : r.dim(decision.failures.map((f) => f.code).join(', '))}`); + } }); + console.log(r.heading('effect boundary')); + console.log(r.field('Listening on', url)); + console.log(r.field('Trusted signers', manifest?.trustedSigners?.join(', ') ?? r.yellow('none pinned — set trustedSigners in pctr.json'))); + console.log(r.field('Replay state', path.join(store.dir(), 'spent-nonces.json'))); + console.log(`\n${r.dim(`Enforce against it with: pctr protect --boundary ${url}`)}`); + await new Promise(() => {}); // serve until interrupted + return 0; + } + + case 'keys': { + const pair = defaultKeyPair(); + const publicKey = exportPublic(pair.publicKey); + if (flag('export') && flag('export') !== true) { + fs.writeFileSync(String(flag('export')), `${publicKey}\n`); + console.log(`Wrote public key to ${flag('export')}`); + } + return out([r.heading('signing keys'), + r.field('Key id', pair.keyId), + r.field('Private key', pair.ephemeral ? r.yellow('ephemeral (not persisted)') : pair.source), + r.field('Algorithm', 'ed25519'), + '', r.dim('Share the public key below. Anyone holding it can verify your receipts'), + r.dim('and cannot mint one. Never share the private key.'), '', publicKey].join('\n'), + { keyId: pair.keyId, algorithm: 'ed25519', publicKey, source: pair.source, ephemeral: pair.ephemeral }); + } + + case 'receipt': { + const receipts = store.listReceipts(); + if (!receipts.length) return fail('No receipts yet. Run: pctr protect '); + const receipt = positional[0] ? receipts.find((x) => x.receiptId === positional[0]) : receipts.at(-1); + if (!receipt) return fail(`No receipt ${positional[0]}`); + return out(r.renderReceipt(receipt, verifyReceipt(receipt, verifyOptions())), receipt); + } + + case 'verify': { + const receipts = store.listReceipts(); + if (!receipts.length) return fail('No receipts to verify yet.'); + const target = positional[0] ? [receipts.find((x) => x.receiptId === positional[0])].filter(Boolean) : receipts; + const opts = verifyOptions(); + const results = target.map((x) => ({ receiptId: x.receiptId, ...verifyReceipt(x, opts) })); + const bad = results.filter((x) => !x.valid); + const unpinned = results.filter((x) => x.valid && !x.signerVerified); + const chain = verifyReceiptChain(receipts, opts); + const human = [r.heading('receipt verification'), + r.field('Receipts checked', String(results.length)), + r.field('Valid', bad.length ? r.red(`${results.length - bad.length} of ${results.length}`) : r.green(String(results.length))), + r.field('Chain', chain.valid ? r.green('intact') : r.red('BROKEN')), + r.field('Signer', unpinned.length + ? r.yellow(`unpinned for ${unpinned.length} receipt(s) — pass --key or set trustedSigners in pctr.json`) + : r.green('verified against a pinned key')), + ...bad.flatMap((b) => [` ${r.red('x')} ${b.receiptId}`, ...b.failures.map((f) => ` ${f.message}`)]), + ...(chain.valid ? [] : chain.failures.flatMap((f) => [` ${r.red('x')} ${f.receiptId}`, ...f.failures.map((x) => ` ${x.message}`)]))].join('\n'); + out(human, { results, chain }); + return bad.length ? 1 : 0; + } + + case 'doctor': { + const manifest = store.readManifest(); + const checks = []; + checks.push(check('pctr.json present', Boolean(manifest), 'Run: pctr init')); + const graph = manifest ? buildGraph(manifest) : null; + if (graph) { + const s = summarize(graph); + checks.push(check('Agents declared', s.agents > 0, 'Add agents to pctr.json')); + checks.push(check('Tools declared', s.tools > 0, 'Add tools with their actions to pctr.json')); + checks.push(check('Protected consequences mapped', s.protected > 0, 'No protected consequence found — verify your action names')); + checks.push(check('Policy defined', Boolean(manifest.policy), `Add a policy block, e.g. ${JSON.stringify(defaultPolicy())}`)); + const noAuthority = [...graph.nodes.values()].filter((n) => n.type === 'agent' && !(n.authority ?? []).length); + checks.push(check('Every agent has declared authority', noAuthority.length === 0, + `No authority declared for: ${noAuthority.map((n) => n.id).join(', ')}`)); + const unreachable = protectedActions(graph).filter((a) => resolveRoute(graph, a.id).admissible.length === 0); + checks.push(check('Protected actions have an admissible route', unreachable.length === 0, + `No admissible route today for: ${unreachable.map((a) => a.id).join(', ')}. That may be correct — it means nothing can currently reach them. Run "pctr route " to see why.`)); + } + const pair = defaultKeyPair(); + checks.push(check('Signing key is persisted', !pair.ephemeral, + 'The signing key is ephemeral, so receipts cannot be verified after this process exits. Make .pctr writable or set PCTR_PRIVATE_KEY.')); + checks.push(check('Trusted signers pinned', Boolean(manifest?.trustedSigners?.length), + `No trustedSigners in pctr.json, so receipts verify as "unpinned". Add "trustedSigners": ["${pair.keyId}"].`)); + if (graph) { + const unmeasured = protectedActions(graph).filter((a) => !(manifest.probes ?? {})[a.id]); + checks.push(check('Protected actions are measured by a probe', unmeasured.length === 0, + `Using declared values for: ${unmeasured.map((a) => a.id).join(', ')}. Add a read-only probe under "probes" to measure the real consequence.`)); + } + const failed = checks.filter((x) => !x.ok); + const human = [r.heading('pctr doctor'), + ...checks.map((x) => `${x.ok ? r.green('ok') : r.yellow('!!')} ${x.label}${x.ok ? '' : `\n ${r.dim(x.fix)}`}`)].join('\n'); + out(human, { checks }); + return failed.length ? 1 : 0; + } + + default: + return fail(`Unknown command: ${command}\n\n${help()}`); + } +} + +const check = (label, ok, fix) => ({ label, ok, fix }); +const fail = (message) => { console.error(message); return 2; }; + +function renderCompare(diff, leftId, rightId) { + const lines = [r.heading('compare runs'), r.field('Left', leftId), r.field('Right', rightId), + r.field('Diverged at step', diff.divergedAt === null ? 'never' : String(diff.divergedAt)), + r.field('Same outcome', diff.sameOutcome ? r.green('YES') : r.red(`NO (${diff.outcomes.join(' vs ')})`)), '']; + for (const row of diff.rows) { + lines.push(`${row.same ? r.dim(' =') : r.yellow(' ~')} ${row.left ?? r.dim('(none)')}`); + if (!row.same) lines.push(` ${r.dim('right:')} ${row.right ?? r.dim('(none)')}`); + } + return lines.join('\n'); +} + +function exampleManifest() { + return { + agents: [ + { id: 'planner', framework: 'openai-agents', trust: 0.98, evidenceAgeSeconds: 20, authority: ['*'], jurisdiction: 'eu', latencyMs: 80, costUnits: 1, tools: [], delegatesTo: ['finance-agent-a', 'finance-agent-d', 'support-agent'] }, + { id: 'finance-agent-a', framework: 'langgraph', trust: 0.97, evidenceAgeSeconds: 4200, authority: ['payments.*'], jurisdiction: 'eu', latencyMs: 90, costUnits: 1, tools: ['payments'] }, + { id: 'finance-agent-d', framework: 'claude-agents', trust: 0.97, evidenceAgeSeconds: 30, authority: ['payments.*'], jurisdiction: 'eu', latencyMs: 140, costUnits: 2, tools: ['payments'] }, + { id: 'support-agent', framework: 'crewai', trust: 0.82, evidenceAgeSeconds: 60, authority: ['customers.read'], jurisdiction: 'eu', latencyMs: 120, costUnits: 1, tools: ['crm'], delegatesTo: ['admin-agent'] }, + { id: 'admin-agent', framework: 'claude-agents', trust: 0.95, evidenceAgeSeconds: 30, authority: ['customers.*'], jurisdiction: 'eu', latencyMs: 200, costUnits: 2, tools: ['database'] } + ], + tools: [ + { id: 'payments', protocol: 'mcp', actions: ['payments.transfer'] }, + { id: 'crm', protocol: 'mcp', actions: ['customers.read'] }, + { id: 'database', protocol: 'mcp', actions: ['customers.delete', 'customers.update'] } + ], + actions: [ + { id: 'payments.transfer', amount: 1800, connectedWorkflows: 2 }, + { id: 'customers.delete', recordsAffected: 1842, connectedWorkflows: 4 } + ] + }; +} + +function help() { + return `PCTR — Protected Consequence Trust Routing + + See what your agents can cause. Route them safely. Prove what happened. + +Usage + pctr init Discover agents and tools, write pctr.json + pctr scan What consequences can your agents reach? + pctr graph Show the trust graph + pctr preview Consequence Twin: what will this change? + pctr route TrustRoute Autopilot: which path may get there? + pctr protect Run the full loop and issue a receipt + pctr simulate Same, without executing any effect + pctr replay [run] Agent Time Machine: what happened, step by step + pctr explain Why was this allowed, denied, or rerouted? + pctr receipt [id] Show an execution receipt + pctr verify [id] Verify receipt signatures and the receipt chain + pctr keys Show your signing key id and public key + pctr serve Run the effect boundary as its own process + pctr doctor Check your setup + +Options + --json Machine-readable output + --amount Material parameter: amount + --records Material parameter: records affected + --params '' Any other material parameters + --approve Record a human approval + --target Execution target + --boundary protect: verify authority at a remote effect boundary + --port serve: port for the effect boundary (default 8787) + --probe preview: measure the real consequence with this probe + --key verify: check signatures against this public key + --export keys: write the public key to a file + --compare replay: diff two runs + --fork [eventId] replay: fork a run for simulation + +Start with: pctr init, then pctr scan`; +} + +main().then((code) => process.exit(code ?? 0)).catch((err) => { + console.error(err.stack ?? String(err)); + process.exit(1); +}); diff --git a/packages/pctr/package.json b/packages/pctr/package.json new file mode 100644 index 0000000..24276b5 --- /dev/null +++ b/packages/pctr/package.json @@ -0,0 +1,12 @@ +{ + "name": "@blocksifr/pctr", + "version": "0.1.0", + "description": "PCTR — Protected Consequence Trust Routing. See what your agents can cause. Route them safely. Prove what happened.", + "type": "module", + "license": "Apache-2.0", + "bin": { "pctr": "./bin/pctr.mjs" }, + "exports": { ".": "./src/index.mjs" }, + "engines": { "node": ">=18" }, + "files": ["src/", "bin/", "README.md"], + "scripts": { "test": "node --test tests/*.test.mjs" } +} diff --git a/packages/pctr/src/adapters.mjs b/packages/pctr/src/adapters.mjs new file mode 100644 index 0000000..c8d6dfe --- /dev/null +++ b/packages/pctr/src/adapters.mjs @@ -0,0 +1,173 @@ +import { classifyAction } from './consequences.mjs'; + +// UNIVERSAL AGENT ENVELOPE. +// Agents are participants, not platforms. An adapter normalizes security *meaning* — +// who is acting, who delegated, what capability appeared, what action is proposed — +// and deliberately drops framework internals. A new framework needs an adapter here, +// not a change to PCTR. + +const str = (...candidates) => candidates.find((c) => typeof c === 'string' && c.length) ?? null; + +// Each adapter maps one framework event to { event, subject, detail } or null when the +// event carries no security meaning. Returning null is a valid, common answer. +export const adapters = { + 'openai-agents': (e) => { + switch (e.type) { + case 'agent_start': case 'run_start': + return { event: 'AGENT_STARTED', subject: str(e.agent, e.agent_name, e.name), detail: { objective: str(e.input, e.objective) } }; + case 'handoff': case 'agent_handoff': + return { event: 'AGENT_DELEGATED', subject: str(e.from_agent, e.source, e.agent), detail: { to: str(e.to_agent, e.target) } }; + case 'tool_call': case 'function_call': + return proposal(str(e.name, e.tool_name, e.function?.name), e.arguments ?? e.args ?? e.input, str(e.agent, e.agent_name)); + case 'tool_output': case 'function_result': + return { event: 'EXECUTION_COMPLETED', subject: str(e.agent, e.agent_name), detail: { action: str(e.name, e.tool_name), status: e.error ? 'FAILED' : 'SUCCEEDED' } }; + default: return null; + } + }, + + 'claude-agents': (e) => { + switch (e.type) { + case 'system': case 'init': + return { event: 'AGENT_STARTED', subject: str(e.session_id, e.agent), detail: { objective: str(e.prompt, e.objective) } }; + case 'tool_use': + return proposal(str(e.name, e.tool), e.input, str(e.agent, e.session_id)); + case 'tool_result': + return { event: 'EXECUTION_COMPLETED', subject: str(e.agent, e.session_id), detail: { action: str(e.name, e.tool), status: e.is_error ? 'FAILED' : 'SUCCEEDED' } }; + case 'subagent': case 'task': + return { event: 'AGENT_DELEGATED', subject: str(e.agent, e.parent, e.session_id), detail: { to: str(e.subagent_type, e.to, e.description) } }; + default: return null; + } + }, + + langgraph: (e) => { + switch (str(e.event, e.type)) { + case 'on_chain_start': case 'on_graph_start': + return { event: 'AGENT_STARTED', subject: str(e.name, e.node), detail: { objective: str(e.data?.input?.objective, e.data?.input) } }; + case 'on_tool_start': + return proposal(str(e.name, e.data?.name), e.data?.input, str(e.metadata?.langgraph_node, e.parent_ids?.at(-1))); + case 'on_tool_end': + return { event: 'EXECUTION_COMPLETED', subject: str(e.metadata?.langgraph_node), detail: { action: str(e.name), status: 'SUCCEEDED' } }; + // A node handing to another node is delegation, whatever the graph calls it. + case 'on_node_start': + return e.metadata?.from + ? { event: 'AGENT_DELEGATED', subject: str(e.metadata.from), detail: { to: str(e.name, e.node) } } + : null; + default: return null; + } + }, + + crewai: (e) => { + switch (str(e.type, e.event)) { + case 'crew_kickoff': case 'task_started': + return { event: 'AGENT_STARTED', subject: str(e.agent, e.agent_role), detail: { objective: str(e.task, e.description) } }; + case 'agent_delegated': case 'delegation': + return { event: 'AGENT_DELEGATED', subject: str(e.from_agent, e.agent), detail: { to: str(e.to_agent, e.coworker) } }; + case 'tool_usage_started': + return proposal(str(e.tool, e.tool_name), e.tool_args ?? e.input, str(e.agent, e.agent_role)); + case 'tool_usage_finished': + return { event: 'EXECUTION_COMPLETED', subject: str(e.agent, e.agent_role), detail: { action: str(e.tool, e.tool_name), status: 'SUCCEEDED' } }; + default: return null; + } + }, + + autogen: (e) => { + switch (str(e.type, e.event)) { + case 'message': case 'chat_message': + // A message that hands work to another participant is a delegation. + return e.recipient && e.sender !== e.recipient + ? { event: 'AGENT_DELEGATED', subject: str(e.sender), detail: { to: str(e.recipient) } } + : null; + case 'function_call': case 'tool_call': + return proposal(str(e.name, e.function?.name), e.arguments ?? e.function?.arguments, str(e.sender, e.agent)); + case 'function_result': case 'tool_response': + return { event: 'EXECUTION_COMPLETED', subject: str(e.sender, e.agent), detail: { action: str(e.name), status: 'SUCCEEDED' } }; + default: return null; + } + }, + + 'semantic-kernel': (e) => { + switch (str(e.type, e.event)) { + case 'function_invoking': + return proposal(str(e.function, e.name, e.function_name), e.arguments, str(e.plugin, e.agent)); + case 'function_invoked': + return { event: 'EXECUTION_COMPLETED', subject: str(e.plugin, e.agent), detail: { action: str(e.function, e.name), status: 'SUCCEEDED' } }; + default: return null; + } + }, + + // MCP speaks JSON-RPC: tools/list is capability discovery, tools/call is a proposal. + mcp: (e) => { + const method = str(e.method, e.type); + if (method === 'tools/list' || method === 'list_tools') { + const tools = (e.result?.tools ?? e.tools ?? []).map((t) => str(t.name, t)).filter(Boolean); + return { event: 'CAPABILITY_DISCOVERED', subject: str(e.server, e.serverName), detail: { tool: str(e.server, e.serverName), actions: tools, protocol: 'mcp' } }; + } + if (method === 'tools/call' || method === 'call_tool') { + return proposal(str(e.params?.name, e.name), e.params?.arguments ?? e.arguments, str(e.client, e.server)); + } + return null; + }, + + a2a: (e) => { + switch (str(e.type, e.event)) { + case 'task.delegated': case 'task/delegate': + return { event: 'AGENT_DELEGATED', subject: str(e.from, e.source_agent), detail: { to: str(e.to, e.target_agent) } }; + case 'task.submitted': case 'task/send': + return { event: 'AGENT_STARTED', subject: str(e.agent, e.to), detail: { objective: str(e.message, e.task?.description) } }; + case 'task.completed': + return { event: 'EXECUTION_COMPLETED', subject: str(e.agent), detail: { action: str(e.task?.name, e.name), status: 'SUCCEEDED' } }; + default: return null; + } + }, + + // Anything can speak the envelope directly. + generic: (e) => { + const action = str(e.action, e.tool, e.name); + if (e.event === 'delegate' || e.delegatesTo) return { event: 'AGENT_DELEGATED', subject: str(e.agent, e.from), detail: { to: str(e.delegatesTo, e.to) } }; + return action ? proposal(action, e.params ?? e.arguments, str(e.agent)) : null; + } +}; + +// A proposed action is where consequence classification happens, so every framework +// gets the same answer to "what can this cause?" from the same rules. +function proposal(action, args, agent) { + if (!action) return null; + const params = typeof args === 'string' ? tryParse(args) : (args ?? {}); + const consequence = classifyAction(action, params); + return { event: 'ACTION_PROPOSED', subject: agent, detail: { action, ...params, consequence: consequence.consequence, severity: consequence.severity } }; +} + +const tryParse = (s) => { try { return JSON.parse(s); } catch { return {}; } }; + +export const supportedFrameworks = () => Object.keys(adapters); + +export function normalize(framework, event) { + const adapter = adapters[framework] ?? adapters.generic; + try { + return adapter(event) ?? null; + } catch { + return null; // A malformed framework event is not a reason to lose the run. + } +} + +// Feed a framework's event stream into a timeline. Proposals also record the +// consequence they imply, because that is the part every framework leaves out. +export function ingest(framework, events, timeline, { because = [] } = {}) { + const recorded = []; + let lastId = because; + for (const raw of events) { + const normalized = normalize(framework, raw); + if (!normalized) continue; + const entry = timeline.record(normalized.event, normalized.detail, { subject: normalized.subject, because: lastId }); + recorded.push(entry); + lastId = [entry.id]; + if (normalized.event === 'ACTION_PROPOSED' && normalized.detail.consequence && normalized.detail.consequence !== 'NONE') { + const detected = timeline.record('CONSEQUENCE_DETECTED', + { consequence: normalized.detail.consequence, severity: normalized.detail.severity, action: normalized.detail.action }, + { subject: normalized.subject, because: [entry.id] }); + recorded.push(detected); + lastId = [detected.id]; + } + } + return recorded; +} diff --git a/packages/pctr/src/authority.mjs b/packages/pctr/src/authority.mjs new file mode 100644 index 0000000..ab3ed82 --- /dev/null +++ b/packages/pctr/src/authority.mjs @@ -0,0 +1,93 @@ +import crypto from 'node:crypto'; +import { hashObj } from '../../../src/util.mjs'; +import { defaultKeyPair, signHash, verifyHash, exportPublic, keyIdFor } from './keys.mjs'; + +// EXECUTION AUTHORITY. +// A valid identity is not enough. A valid credential is not enough. A valid route is +// not enough. Authority is bound to the exact consequential execution, and the +// execution boundary verifies it independently of the agent that requested it. + +export function issueAuthority({ + principal, delegator = null, session = null, action, target, params = {}, + constraints = {}, policyVersion = 'local-v1', consequence, route, + validForSeconds = 300, issuedAt = new Date().toISOString(), keyPair = defaultKeyPair() +}) { + const materialParams = selectMaterial(params, constraints.materialParams); + const expiresAt = new Date(new Date(issuedAt).getTime() + validForSeconds * 1000).toISOString(); + const envelope = { + type: 'TTPExecutionAuthority', version: 1, + principal, delegator, session, + action, target, materialParams, + constraints, policyVersion, consequence, + routeId: route?.routeId ?? null, routeHash: route?.routeHash ?? null, + issuedAt, expiresAt, nonce: crypto.randomUUID(), + // The signer's identity is inside the binding, so a signature cannot be re-attached + // to the same authority under a different key. + keyId: keyPair.keyId ?? keyIdFor(keyPair.publicKey) + }; + const bindingHash = hashObj(envelope); + return { ...envelope, bindingHash, signature: signHash(bindingHash, keyPair), signerPublicKey: exportPublic(keyPair.publicKey) }; +} + +// The effect boundary. It re-derives the binding from what is ACTUALLY about to +// execute and compares. A requesting agent cannot enforce its own authority. +export function verifyAuthority(authority, execution, { now = new Date().toISOString(), publicKey, trustedKeyIds, replayStore } = {}) { + const failures = []; + const { bindingHash, signature, signerPublicKey, ...envelope } = authority ?? {}; + if (!authority) return deny([{ code: 'AUTHORITY_MISSING', message: 'no execution authority presented' }]); + + if (hashObj(envelope) !== bindingHash) failures.push({ code: 'BINDING_HASH_MISMATCH', message: 'authority contents do not match their binding' }); + + // Verifying with a key supplied by the caller is the real check. Falling back to the + // key carried inside the authority proves only internal consistency, and says so. + const key = publicKey ?? signerPublicKey; + const signerVerified = Boolean(publicKey) || (Array.isArray(trustedKeyIds) && trustedKeyIds.includes(envelope.keyId)); + if (!key) failures.push({ code: 'SIGNATURE_INVALID', message: 'authority carries no verification key' }); + else if (!verifyHash(bindingHash, signature, key)) failures.push({ code: 'SIGNATURE_INVALID', message: 'authority signature does not verify' }); + else if (signature?.keyId !== envelope.keyId) failures.push({ code: 'SIGNER_MISMATCH', message: 'signature key id does not match the key id bound into the authority' }); + if (Array.isArray(trustedKeyIds) && !trustedKeyIds.includes(envelope.keyId)) { + failures.push({ code: 'UNTRUSTED_SIGNER', message: `authority was signed by ${envelope.keyId}, which is not a trusted signer` }); + } + + if (new Date(now) > new Date(envelope.expiresAt)) failures.push({ code: 'AUTHORITY_EXPIRED', message: `authority expired at ${envelope.expiresAt}` }); + if (new Date(now) < new Date(envelope.issuedAt)) failures.push({ code: 'AUTHORITY_NOT_YET_VALID', message: 'authority is not yet valid' }); + + if (execution.action !== envelope.action) failures.push({ code: 'ACTION_MISMATCH', message: `authority binds ${envelope.action}, execution is ${execution.action}` }); + if (execution.target !== envelope.target) failures.push({ code: 'TARGET_MISMATCH', message: `authority binds ${envelope.target}, execution targets ${execution.target}` }); + if (execution.principal && execution.principal !== envelope.principal) failures.push({ code: 'PRINCIPAL_MISMATCH', message: 'execution principal differs from the authorized principal' }); + + const executed = selectMaterial(execution.params ?? {}, Object.keys(envelope.materialParams ?? {})); + for (const [key, value] of Object.entries(envelope.materialParams ?? {})) { + if (!deepEqual(executed[key], value)) { + failures.push({ code: 'PARAMETER_MISMATCH', message: `${key} was authorized as ${JSON.stringify(value)} but is ${JSON.stringify(executed[key])}` }); + } + } + for (const [key, limit] of Object.entries(envelope.constraints?.max ?? {})) { + if (Number(execution.params?.[key]) > Number(limit)) { + failures.push({ code: 'CONSTRAINT_EXCEEDED', message: `${key} is ${execution.params[key]}, above the authorized maximum of ${limit}` }); + } + } + if (envelope.constraints?.requiresApproval && !execution.approval) { + failures.push({ code: 'APPROVAL_MISSING', message: 'this authority requires a recorded human approval' }); + } + if (replayStore?.seen(envelope.nonce)) failures.push({ code: 'REPLAYED_AUTHORITY', message: 'this authority has already been spent' }); + + if (failures.length === 0) replayStore?.spend(envelope.nonce); + return failures.length + ? { ...deny(failures), signerVerified } + : { allowed: true, decision: 'EXECUTION_ALLOWED', bindingHash, failures: [], verifiedAt: now, signerVerified, + warnings: signerVerified ? [] : [{ code: 'UNPINNED_KEY', message: 'signature is internally consistent, but the signer was not pinned; pass publicKey or trustedKeyIds to verify who signed it' }] }; +} + +const deny = (failures) => ({ allowed: false, decision: 'EXECUTION_DENIED', failures }); + +export function createReplayStore(initial = []) { + const spent = new Set(initial); + return { seen: (n) => spent.has(n), spend: (n) => spent.add(n), list: () => [...spent] }; +} + +function selectMaterial(params, keys) { + if (!keys?.length) return { ...params }; + return Object.fromEntries(keys.filter((k) => k in params).map((k) => [k, params[k]])); +} +const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b); diff --git a/packages/pctr/src/boundary.mjs b/packages/pctr/src/boundary.mjs new file mode 100644 index 0000000..e6f8e50 --- /dev/null +++ b/packages/pctr/src/boundary.mjs @@ -0,0 +1,91 @@ +import http from 'node:http'; +import fs from 'node:fs'; +import path from 'node:path'; +import { verifyAuthority, createReplayStore } from './authority.mjs'; + +// THE EFFECT BOUNDARY. +// The requesting agent must not be trusted to enforce its own authority, so the check +// belongs somewhere the agent does not control: a separate process that holds the +// replay state and the list of signers it will accept. + +// Spent nonces must survive a restart, or replay protection lasts only as long as uptime. +export function persistentReplayStore(file) { + let spent = new Set(); + try { spent = new Set(JSON.parse(fs.readFileSync(file, 'utf8'))); } catch { /* first run */ } + const flush = () => { + fs.mkdirSync(path.dirname(file), { recursive: true }); + fs.writeFileSync(file, JSON.stringify([...spent])); + }; + return { + seen: (nonce) => spent.has(nonce), + spend: (nonce) => { spent.add(nonce); flush(); }, + list: () => [...spent] + }; +} + +export function createBoundary({ trustedKeyIds, publicKey, replayStore = createReplayStore(), name = 'pctr.effect-boundary' } = {}) { + return { + name, + verify(authority, execution, { now } = {}) { + const result = verifyAuthority(authority, execution, { now, publicKey, trustedKeyIds, replayStore }); + return { ...result, boundary: name, verifiedAt: result.verifiedAt ?? new Date().toISOString() }; + }, + replayStore + }; +} + +export function startBoundaryServer({ port = 8787, host = '127.0.0.1', boundary = createBoundary(), onDecision } = {}) { + const server = http.createServer((req, res) => { + const send = (code, body) => { + res.writeHead(code, { 'content-type': 'application/json' }); + res.end(JSON.stringify(body)); + }; + if (req.method === 'GET' && req.url === '/health') { + return send(200, { ok: true, boundary: boundary.name, spentNonces: boundary.replayStore.list().length }); + } + if (req.method !== 'POST' || req.url !== '/verify') return send(404, { error: 'POST /verify or GET /health' }); + + let body = ''; + req.on('data', (chunk) => { + body += chunk; + if (body.length > 1_000_000) req.destroy(); // an authority is small; anything larger is not one + }); + req.on('end', () => { + let parsed; + try { parsed = JSON.parse(body); } catch { return send(400, { error: 'invalid JSON' }); } + const { authority, execution } = parsed ?? {}; + if (!execution) return send(400, { error: 'execution is required: the boundary checks authority against what is actually about to run' }); + const decision = boundary.verify(authority, execution); + onDecision?.(decision, { authority, execution }); + // A denial is a successful verification, so it is still 200 with a decision body. + return send(200, decision); + }); + }); + return new Promise((resolve) => { + server.listen(port, host, () => resolve({ server, url: `http://${host}:${server.address().port}`, close: () => new Promise((r) => server.close(r)) })); + }); +} + +// Client side. A network failure is never an allow: if the boundary cannot be reached, +// the execution is denied. +export function remoteBoundary(url, { timeoutMs = 5000 } = {}) { + return { + name: url, + async verify(authority, execution) { + try { + const response = await fetch(`${url.replace(/\/$/, '')}/verify`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ authority, execution }), + signal: AbortSignal.timeout(timeoutMs) + }); + if (!response.ok) { + return { allowed: false, decision: 'EXECUTION_DENIED', boundary: url, failures: [{ code: 'BOUNDARY_ERROR', message: `effect boundary returned ${response.status}` }] }; + } + return { ...(await response.json()), boundary: url }; + } catch (error) { + return { allowed: false, decision: 'EXECUTION_DENIED', boundary: url, failures: [{ code: 'BOUNDARY_UNREACHABLE', message: `effect boundary at ${url} could not be reached: ${error.message}` }] }; + } + } + }; +} diff --git a/packages/pctr/src/consequences.mjs b/packages/pctr/src/consequences.mjs new file mode 100644 index 0000000..24f2e28 --- /dev/null +++ b/packages/pctr/src/consequences.mjs @@ -0,0 +1,73 @@ +// Protected consequences come first. An action matters because of the state change +// it can cause, not because of which agent happens to hold the credential. + +export const CONSEQUENCE_CLASSES = { + MONEY_MOVED: { label: 'money moved', severity: 'HIGH', reversible: false }, + DATA_DELETED: { label: 'data deleted', severity: 'CRITICAL', reversible: false }, + IDENTITY_CHANGED: { label: 'identity disabled or changed', severity: 'HIGH', reversible: true }, + SECRET_EXPOSED: { label: 'secret exposed', severity: 'CRITICAL', reversible: false }, + PRODUCTION_CHANGED: { label: 'production changed', severity: 'HIGH', reversible: true }, + INFRA_MODIFIED: { label: 'infrastructure modified', severity: 'HIGH', reversible: true }, + ACCESS_GRANTED: { label: 'access granted', severity: 'HIGH', reversible: true }, + MESSAGE_SENT: { label: 'external message sent', severity: 'MEDIUM', reversible: false }, + CONTRACT_EXECUTED: { label: 'contract executed', severity: 'CRITICAL', reversible: false }, + PHYSICAL_CHANGED: { label: 'physical system changed', severity: 'CRITICAL', reversible: false }, + DATA_WRITTEN: { label: 'data written', severity: 'MEDIUM', reversible: true }, + DATA_READ: { label: 'data read', severity: 'LOW', reversible: true }, + NONE: { label: 'no protected consequence', severity: 'LOW', reversible: true } +}; + +// The verb decides, not the namespace: payments.status reads, payments.transfer moves +// money. A read verb in the final segment settles the question before anything else. +const READ_VERB = /(?:^|[.\/_:-])(get|list|read|status|search|query|fetch|describe|show|view|count|preview)$/i; + +// Ordered: first match wins, so the destructive readings are checked before the mild ones. +const RULES = [ + [/(payment|transfer|payout|refund|charge|wire|treasury|stripe|ledger\.move|\bpay\b)/i, 'MONEY_MOVED'], + [/(delete|destroy|drop|purge|truncate|wipe|erase|remove_all|terminate)/i, 'DATA_DELETED'], + [/(secret|credential|token|apikey|api_key|private_key|vault\.read|password)/i, 'SECRET_EXPOSED'], + [/(contract|sign|execute_agreement|onchain|smart_contract)/i, 'CONTRACT_EXECUTED'], + [/(device|actuator|valve|door|robot|plc|scada)/i, 'PHYSICAL_CHANGED'], + [/(disable_user|deactivate|suspend_user|user\.update|identity|scim|role\.assign)/i, 'IDENTITY_CHANGED'], + [/(grant|permission|policy\.attach|share|acl|invite)/i, 'ACCESS_GRANTED'], + [/(deploy|release|rollback|migrate|prod|k8s\.apply|helm)/i, 'PRODUCTION_CHANGED'], + [/(terraform|infra|instance|bucket|dns|firewall|network|cluster)/i, 'INFRA_MODIFIED'], + [/(send|email|slack|sms|post_message|notify|publish|tweet)/i, 'MESSAGE_SENT'], + [/(write|create|update|insert|upsert|patch|put)/i, 'DATA_WRITTEN'], + [/(read|get|list|search|query|select|fetch)/i, 'DATA_READ'] +]; + +export function classifyAction(actionId, hints = {}) { + if (hints.consequence && CONSEQUENCE_CLASSES[hints.consequence]) { + return decorate(actionId, hints.consequence, hints); + } + if (READ_VERB.test(actionId)) return decorate(actionId, 'DATA_READ', hints); + for (const [pattern, cls] of RULES) { + if (pattern.test(actionId)) return decorate(actionId, cls, hints); + } + return decorate(actionId, 'NONE', hints); +} + +const RANK = { LOW: 0, MEDIUM: 1, HIGH: 2, CRITICAL: 3 }; +export const severityRank = (s) => RANK[s] ?? 0; +export const maxSeverity = (a, b) => (severityRank(a) >= severityRank(b) ? a : b); + +function decorate(actionId, cls, hints) { + const base = CONSEQUENCE_CLASSES[cls]; + let severity = hints.severity ?? base.severity; + const reversible = hints.reversible ?? base.reversible; + // Scale and money both raise the stakes beyond the action name itself. + if (hints.recordsAffected >= 1000 || hints.amount >= 5000) severity = maxSeverity(severity, 'CRITICAL'); + else if (hints.recordsAffected >= 100 || hints.amount >= 500) severity = maxSeverity(severity, 'HIGH'); + return { + action: actionId, + consequence: cls, + label: base.label, + severity, + reversible, + protected: cls !== 'NONE' && severityRank(severity) >= RANK.MEDIUM + }; +} + +// A protected action is one whose consequence must not occur on credential possession alone. +export const isProtected = (actionId, hints) => classifyAction(actionId, hints).protected; diff --git a/packages/pctr/src/discover.mjs b/packages/pctr/src/discover.mjs new file mode 100644 index 0000000..b4a1d8d --- /dev/null +++ b/packages/pctr/src/discover.mjs @@ -0,0 +1,180 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +// Agents are participants, not platforms. Discovery normalizes whatever a project +// happens to use into the universal agent envelope: agent, tool, action. + +const FRAMEWORKS = [ + [/^openai$/, 'openai-agents'], [/^@openai\//, 'openai-agents'], + [/^@anthropic-ai\//, 'claude-agents'], [/claude-agent-sdk/, 'claude-agents'], + [/^@google\/|google-generativeai|google-genai/, 'google-agents'], + [/langgraph/, 'langgraph'], [/^langchain|^@langchain\//, 'langchain'], + [/crewai/, 'crewai'], [/autogen|pyautogen/, 'autogen'], + [/semantic-kernel|semantic_kernel/, 'semantic-kernel'], + [/^@modelcontextprotocol\/|^mcp$/, 'mcp'], [/a2a/, 'a2a'] +]; + +const MCP_CONFIGS = ['.mcp.json', 'mcp.json', '.claude/settings.json', 'claude_desktop_config.json']; +const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.venv', 'venv', '__pycache__', '.pctr']); +const SOURCE_FILE = /\.(m?[jt]sx?|py)$/; +const MAX_FILE_BYTES = 512 * 1024; + +// Tool and agent declarations are written down in source; a running server is not +// needed to read them. These patterns cover how the common frameworks name things. +// Anything not matched is simply not discovered — never guessed. +const TOOL_PATTERNS = [ + /\b(?:server|mcp|app)\.(?:tool|registerTool)\s*\(\s*['"`]([\w.\-:/]+)['"`]/g, // MCP servers (JS) + /new\s+(?:DynamicStructuredTool|DynamicTool|Tool)\s*\(\s*\{\s*name\s*:\s*['"`]([\w.\-:/]+)['"`]/g, // LangChain + /\btool\s*\(\s*\{\s*name\s*:\s*['"`]([\w.\-:/]+)['"`]/g, // OpenAI / generic tool() + /['"`]?name['"`]?\s*:\s*['"`]([\w.\-:/]+)['"`]\s*,\s*['"`]?description['"`]?\s*:/g, // tool schema objects + /@(?:mcp|server|app)\.tool\s*\([^)]*\)\s*(?:async\s+)?def\s+(\w+)/g, // FastMCP (Python) + /@tool\s*(?:\([^)]*\))?\s*(?:async\s+)?def\s+(\w+)/g, // LangChain (Python) + /\bTool\s*\(\s*name\s*=\s*['"]([\w.\-:/]+)['"]/g // CrewAI / generic (Python) +]; +const AGENT_PATTERNS = [ + /new\s+Agent\s*\(\s*\{[^}]*?name\s*:\s*['"`]([\w.\- ]+)['"`]/g, + /\bAgent\s*\(\s*(?:role|name)\s*=\s*['"]([\w.\- ]+)['"]/g, + /create(?:React|Tool[\w]*)?Agent\s*\(\s*\{[^}]*?name\s*:\s*['"`]([\w.\- ]+)['"`]/g, + /\bAssistantAgent\s*\(\s*(?:name\s*=\s*)?['"]([\w.\- ]+)['"]/g +]; + +export function discover(cwd = process.cwd(), { declared = null } = {}) { + const agents = new Map(); + const tools = new Map(); + const notes = []; + + for (const [name, framework] of detectFrameworks(cwd)) { + notes.push(`${framework} detected via dependency "${name}"`); + } + const frameworks = [...new Set(detectFrameworks(cwd).map(([, f]) => f))]; + + // Read the source once and take both agents and tool actions from it. + const sources = findSourceFiles(cwd); + const actionsByFile = new Map(); + for (const file of sources) { + let text; + try { + if (fs.statSync(file).size > MAX_FILE_BYTES) continue; + text = fs.readFileSync(file, 'utf8'); + } catch { continue; } + + const declaredActions = extractAll(TOOL_PATTERNS, text); + if (declaredActions.length) actionsByFile.set(file, declaredActions); + + for (const name of extractAll(AGENT_PATTERNS, text)) { + const id = slug(name); + agents.set(id, { id, framework: frameworkFor(text, frameworks), source: path.relative(cwd, file), trust: 0.7, evidenceAgeSeconds: 0, authority: [], tools: [] }); + notes.push(`agent "${name}" declared in ${path.relative(cwd, file)}`); + } + if (/agent/i.test(path.basename(file)) && !extractAll(AGENT_PATTERNS, text).length) { + const id = slug(path.basename(file).replace(SOURCE_FILE, '')); + if (!agents.has(id)) agents.set(id, { id, framework: frameworkFor(text, frameworks), source: path.relative(cwd, file), trust: 0.7, evidenceAgeSeconds: 0, authority: [], tools: [] }); + } + } + + for (const [file, actions] of actionsByFile) { + const id = slug(path.basename(path.dirname(file)) === '.' ? 'local-tools' : `${path.basename(file).replace(SOURCE_FILE, '')}-tools`); + tools.set(id, { id, protocol: 'local', actions: [...new Set(actions)], source: path.relative(cwd, file) }); + notes.push(`${actions.length} action(s) declared in ${path.relative(cwd, file)}`); + } + + for (const cfg of MCP_CONFIGS) { + const p = path.join(cwd, cfg); + if (!fs.existsSync(p)) continue; + let parsed; try { parsed = JSON.parse(fs.readFileSync(p, 'utf8')); } catch { continue; } + const servers = parsed.mcpServers ?? parsed.servers ?? {}; + for (const [name, def] of Object.entries(servers)) { + tools.set(name, { id: name, protocol: 'mcp', actions: def.actions ?? [], source: cfg }); + notes.push(`MCP server "${name}" found in ${cfg}`); + } + } + + // Declared facts always win over inferred ones: a manifest is ground truth. + // A discovered agent with no declared tools is assumed to reach the tools found + // alongside it — an over-broad first draft is safer than an incomplete map, and the + // manifest is there to be corrected. + const toolIds = [...tools.keys()]; + for (const agent of agents.values()) if (!agent.tools.length) agent.tools = toolIds; + + const manifest = { + version: 1, + principal: declared?.principal ?? 'user:local', + frameworks, + agents: mergeById([...agents.values()], declared?.agents ?? []), + tools: mergeById([...tools.values()], declared?.tools ?? []), + actions: declared?.actions ?? [], + policy: declared?.policy ?? defaultPolicy() + }; + return { manifest, notes, discovered: { agents: agents.size, tools: tools.size } }; +} + +export const defaultPolicy = () => ({ + requireApprovalAtOrAbove: 'CRITICAL', + maxHops: 6, + decayPerHop: 0.05, + approvalThresholds: { amount: 5000 } +}); + +function mergeById(inferred, declaredList) { + const out = new Map(inferred.map((x) => [x.id, x])); + for (const d of declaredList) out.set(d.id, { ...(out.get(d.id) ?? {}), ...d }); + return [...out.values()]; +} + +function detectFrameworks(cwd) { + const found = []; + const pkgPath = path.join(cwd, 'package.json'); + if (fs.existsSync(pkgPath)) { + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + const deps = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies }); + for (const d of deps) for (const [re, f] of FRAMEWORKS) if (re.test(d)) found.push([d, f]); + } catch { /* an unreadable package.json is not a discovery failure */ } + } + for (const f of ['requirements.txt', 'pyproject.toml']) { + const p = path.join(cwd, f); + if (!fs.existsSync(p)) continue; + const text = fs.readFileSync(p, 'utf8'); + for (const [re, fw] of FRAMEWORKS) if (re.test(text) || new RegExp(re.source.replace(/[\^$]/g, ''), 'i').test(text)) found.push([f, fw]); + } + return found; +} + +const slug = (name) => name.trim().toLowerCase().replace(/[_\s]+/g, '-').replace(/[^a-z0-9.\-]/g, ''); + +function extractAll(patterns, text) { + const found = []; + for (const pattern of patterns) { + pattern.lastIndex = 0; + let match; + while ((match = pattern.exec(text)) !== null) if (match[1]) found.push(match[1]); + } + return [...new Set(found)]; +} + +// What a file imports is better evidence than what the project depends on overall. +const FILE_FRAMEWORKS = [ + [/from\s+crewai|import\s+crewai/, 'crewai'], + [/autogen/, 'autogen'], + [/langgraph/, 'langgraph'], + [/from\s+langchain|@langchain\//, 'langchain'], + [/semantic[_-]kernel/, 'semantic-kernel'], + [/@modelcontextprotocol\/|from\s+mcp/, 'mcp'], + [/@anthropic-ai\/|claude[_-]agent/, 'claude-agents'], + [/\bopenai\b/, 'openai-agents'] +]; +const frameworkFor = (text, frameworks) => + FILE_FRAMEWORKS.find(([re]) => re.test(text))?.[1] ?? frameworks[0] ?? 'unknown'; + +function findSourceFiles(cwd, depth = 0) { + if (depth > 3) return []; + let entries; try { entries = fs.readdirSync(cwd, { withFileTypes: true }); } catch { return []; } + const out = []; + for (const e of entries) { + if (e.name.startsWith('.') && e.name !== '.claude') continue; + const full = path.join(cwd, e.name); + if (e.isDirectory()) { if (!SKIP_DIRS.has(e.name)) out.push(...findSourceFiles(full, depth + 1)); } + else if (SOURCE_FILE.test(e.name) && !/\.(test|spec)\./.test(e.name)) out.push(full); + } + return out; +} diff --git a/packages/pctr/src/events.mjs b/packages/pctr/src/events.mjs new file mode 100644 index 0000000..e958ab7 --- /dev/null +++ b/packages/pctr/src/events.mjs @@ -0,0 +1,10 @@ +// Canonical PCTR security events. Frameworks emit whatever they emit; adapters +// normalize into these. The set is the shared security meaning, not framework internals. +export const EVENTS = [ + 'AGENT_DISCOVERED','AGENT_STARTED','AGENT_DELEGATED','CAPABILITY_DISCOVERED', + 'ACTION_PROPOSED','CONSEQUENCE_DETECTED','TRUST_CHANGED','ROUTE_SELECTED','ROUTE_INVALIDATED', + 'AUTHORITY_REQUESTED','AUTHORITY_ISSUED','EXECUTION_REQUESTED','EXECUTION_ALLOWED', + 'EXECUTION_DENIED','EXECUTION_COMPLETED','RECEIPT_ISSUED' +]; +const SET = new Set(EVENTS); +export const isCanonicalEvent = (name) => SET.has(name); diff --git a/packages/pctr/src/graph.mjs b/packages/pctr/src/graph.mjs new file mode 100644 index 0000000..965ed62 --- /dev/null +++ b/packages/pctr/src/graph.mjs @@ -0,0 +1,116 @@ +import { classifyAction, severityRank } from './consequences.mjs'; + +// The graph is the visual model of execution authority, not a decorative dashboard. +// Nodes: principal -> agents -> tools -> actions -> consequences. + +export function buildGraph(manifest) { + const nodes = new Map(); + const edges = []; + const add = (id, type, data = {}) => { + if (!nodes.has(id)) nodes.set(id, { id, type, ...data }); + else Object.assign(nodes.get(id), data); + return nodes.get(id); + }; + const link = (from, to, kind) => { edges.push({ from, to, kind }); }; + + const principal = manifest.principal ?? 'principal:local'; + add(principal, 'principal'); + + const toolById = new Map((manifest.tools ?? []).map((t) => [t.id, t])); + const actionHints = new Map((manifest.actions ?? []).map((a) => [a.id, a])); + + for (const agent of manifest.agents ?? []) { + add(agent.id, 'agent', { + framework: agent.framework ?? 'unknown', + trust: agent.trust ?? 0, + evidenceAgeSeconds: agent.evidenceAgeSeconds ?? 0, + jurisdiction: agent.jurisdiction ?? null, + authority: agent.authority ?? [], + latencyMs: agent.latencyMs ?? 0, + costUnits: agent.costUnits ?? 0, + available: agent.available !== false + }); + if (agent.entry !== false && !(manifest.agents ?? []).some((a) => (a.delegatesTo ?? []).includes(agent.id))) { + link(principal, agent.id, 'delegates'); + } + for (const target of agent.delegatesTo ?? []) link(agent.id, target, 'delegates'); + for (const toolId of agent.tools ?? []) link(agent.id, toolId, 'uses'); + } + + for (const tool of manifest.tools ?? []) { + add(tool.id, 'tool', { protocol: tool.protocol ?? 'local' }); + for (const actionId of tool.actions ?? []) { + const hints = actionHints.get(actionId) ?? {}; + const c = classifyAction(actionId, hints); + add(actionId, 'action', { ...c, ...hints }); + link(tool.id, actionId, 'performs'); + const consequenceId = `consequence:${c.consequence}`; + add(consequenceId, 'consequence', { class: c.consequence, label: c.label, severity: c.severity }); + link(actionId, consequenceId, 'causes'); + } + } + + return { principal, nodes, edges, manifest }; +} + +export const outgoing = (graph, id, kind) => + graph.edges.filter((e) => e.from === id && (!kind || e.kind === kind)).map((e) => e.to); +export const incoming = (graph, id, kind) => + graph.edges.filter((e) => e.to === id && (!kind || e.kind === kind)).map((e) => e.from); + +// Forward: what consequential state changes can this agent eventually reach? +export function reachableActions(graph, agentId, seen = new Set()) { + if (seen.has(agentId)) return []; + seen.add(agentId); + const found = []; + for (const toolId of outgoing(graph, agentId, 'uses')) { + for (const actionId of outgoing(graph, toolId, 'performs')) found.push({ actionId, toolId, via: [agentId] }); + } + for (const next of outgoing(graph, agentId, 'delegates')) { + for (const r of reachableActions(graph, next, seen)) found.push({ ...r, via: [agentId, ...r.via] }); + } + return found; +} + +// Inverse: consequence <- action <- tool <- agent <- delegation <- principal. +// Every distinct path that can arrive at this consequence. +export function pathsToAction(graph, actionId) { + const toolIds = incoming(graph, actionId, 'performs'); + const paths = []; + const walkBack = (agentId, tail, seen) => { + if (seen.has(agentId)) return; + const next = new Set(seen).add(agentId); + const path = [agentId, ...tail]; + const delegators = incoming(graph, agentId, 'delegates'); + if (!delegators.length) { paths.push([graph.principal, ...path]); return; } + for (const d of delegators) { + if (d === graph.principal) paths.push([graph.principal, ...path]); + else walkBack(d, path, next); + } + }; + for (const toolId of toolIds) { + for (const agentId of incoming(graph, toolId, 'uses')) walkBack(agentId, [toolId, actionId], new Set()); + } + return paths; +} + +export function protectedActions(graph) { + return [...graph.nodes.values()] + .filter((n) => n.type === 'action' && n.protected) + .sort((a, b) => severityRank(b.severity) - severityRank(a.severity) || a.id.localeCompare(b.id)); +} + +export function summarize(graph) { + const counts = { agents: 0, tools: 0, actions: 0, consequences: 0 }; + const bySeverity = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 }; + for (const n of graph.nodes.values()) { + if (n.type === 'agent') counts.agents++; + if (n.type === 'tool') counts.tools++; + if (n.type === 'action') { counts.actions++; bySeverity[n.severity]++; } + if (n.type === 'consequence') counts.consequences++; + } + const externalSystems = new Set( + [...graph.nodes.values()].filter((n) => n.type === 'tool' && n.protocol !== 'local').map((n) => n.id) + ).size; + return { ...counts, externalSystems, bySeverity, protected: protectedActions(graph).length }; +} diff --git a/packages/pctr/src/index.mjs b/packages/pctr/src/index.mjs new file mode 100644 index 0000000..8c8583f --- /dev/null +++ b/packages/pctr/src/index.mjs @@ -0,0 +1,17 @@ +export * from './consequences.mjs'; +export * from './graph.mjs'; +export * from './trust.mjs'; +export * from './router.mjs'; +export * from './twin.mjs'; +export * from './authority.mjs'; +export * from './receipt.mjs'; +export * from './timeline.mjs'; +export * from './discover.mjs'; +export * from './observe.mjs'; +export * from './adapters.mjs'; +export * from './probe.mjs'; +export * from './boundary.mjs'; +export * from './keys.mjs'; +export * from './protect.mjs'; +export { EVENTS, isCanonicalEvent } from './events.mjs'; +export * as store from './store.mjs'; diff --git a/packages/pctr/src/keys.mjs b/packages/pctr/src/keys.mjs new file mode 100644 index 0000000..56ba95f --- /dev/null +++ b/packages/pctr/src/keys.mjs @@ -0,0 +1,78 @@ +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; + +// Ed25519 signing, so a receipt can be verified by someone who cannot mint one. +// The key id is derived from the public key, which binds an embedded key to its id: +// swapping in another public key changes the id and breaks any pin against it. + +export const keyIdFor = (publicKey) => + `ed25519:${crypto.createHash('sha256').update(exportPublic(publicKey)).digest('hex').slice(0, 32)}`; + +export function generateKeyPair() { + const { privateKey, publicKey } = crypto.generateKeyPairSync('ed25519'); + return { privateKey, publicKey, keyId: keyIdFor(publicKey) }; +} + +export const exportPublic = (publicKey) => + (typeof publicKey === 'string' ? publicKey : publicKey.export({ type: 'spki', format: 'pem' })).trim(); + +export const exportPrivate = (privateKey) => + privateKey.export({ type: 'pkcs8', format: 'pem' }); + +export const publicKeyFrom = (pem) => + (typeof pem === 'string' ? crypto.createPublicKey(pem) : pem); + +export function keyPairFromPrivatePem(pem) { + const privateKey = crypto.createPrivateKey(pem); + const publicKey = crypto.createPublicKey(privateKey); + return { privateKey, publicKey, keyId: keyIdFor(publicKey) }; +} + +// Keys live beside the run store. The private key is written 0600 and is the one file +// in .pctr that must never be committed or shared. +export function loadOrCreateKeyPair(dir) { + const privatePath = path.join(dir, 'signing-key.pem'); + const publicPath = path.join(dir, 'verification-key.pem'); + if (fs.existsSync(privatePath)) return { ...keyPairFromPrivatePem(fs.readFileSync(privatePath, 'utf8')), path: privatePath, created: false }; + + const pair = generateKeyPair(); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(privatePath, exportPrivate(pair.privateKey), { mode: 0o600 }); + fs.writeFileSync(publicPath, `${exportPublic(pair.publicKey)}\n`); + return { ...pair, path: privatePath, created: true }; +} + +let cached = null; +// Resolution order: an explicit PEM in the environment, then the local key store, then +// an ephemeral in-memory key. An ephemeral key still produces valid signatures — they +// just cannot be verified after the process exits, so it is reported as such. +export function defaultKeyPair({ cwd = process.cwd(), reset = false } = {}) { + if (reset) cached = null; + if (cached) return cached; + if (process.env.PCTR_PRIVATE_KEY) { + cached = { ...keyPairFromPrivatePem(process.env.PCTR_PRIVATE_KEY), source: 'env:PCTR_PRIVATE_KEY', ephemeral: false }; + return cached; + } + try { + const pair = loadOrCreateKeyPair(path.join(cwd, '.pctr', 'keys')); + cached = { ...pair, source: pair.path, ephemeral: false }; + } catch { + cached = { ...generateKeyPair(), source: 'ephemeral (no writable key store)', ephemeral: true }; + } + return cached; +} + +export function signHash(hash, keyPair = defaultKeyPair()) { + const signature = crypto.sign(null, Buffer.from(hash), keyPair.privateKey).toString('base64'); + return { alg: 'ed25519', keyId: keyPair.keyId ?? keyIdFor(keyPair.publicKey), value: signature }; +} + +export function verifyHash(hash, signature, publicKey) { + if (!signature || signature.alg !== 'ed25519' || !signature.value) return false; + try { + return crypto.verify(null, Buffer.from(hash), publicKeyFrom(publicKey), Buffer.from(signature.value, 'base64')); + } catch { + return false; + } +} diff --git a/packages/pctr/src/observe.mjs b/packages/pctr/src/observe.mjs new file mode 100644 index 0000000..6229557 --- /dev/null +++ b/packages/pctr/src/observe.mjs @@ -0,0 +1,45 @@ +import { outgoing } from './graph.mjs'; +import { agentTrustNow } from './trust.mjs'; + +// Discovery is an observed security event too: what exists, who delegated to whom, and +// what each participant can reach. This is what turns a static graph into a run. +export function recordDiscovery(graph, timeline) { + const agents = [...graph.nodes.values()].filter((n) => n.type === 'agent'); + for (const agent of agents) { + const discovered = timeline.record('AGENT_DISCOVERED', + { framework: agent.framework, trust: agent.trust, authority: agent.authority }, { subject: agent.id }); + for (const target of outgoing(graph, agent.id, 'delegates')) { + timeline.record('AGENT_DELEGATED', { to: target }, { subject: agent.id, because: [discovered.id] }); + } + for (const toolId of outgoing(graph, agent.id, 'uses')) { + const actions = outgoing(graph, toolId, 'performs'); + timeline.record('CAPABILITY_DISCOVERED', + { tool: toolId, actions, protocol: graph.nodes.get(toolId)?.protocol ?? 'local' }, + { subject: agent.id, because: [discovered.id] }); + } + } + return timeline; +} + +// Trust is observed, not assumed. Comparing the trust state behind the previously +// selected route with the state now is what makes TRUST_CHANGED real rather than decorative. +export function trustDelta(previousStates = [], currentStates = []) { + const before = new Map(previousStates.map((t) => [t.agentId, t])); + const changes = []; + for (const now of currentStates) { + const was = before.get(now.agentId); + if (!was) continue; + if (was.trust !== now.trust || was.evidenceStale !== now.evidenceStale) { + changes.push({ + agentId: now.agentId, from: was.trust, to: now.trust, + becameStale: !was.evidenceStale && now.evidenceStale, + reason: !was.evidenceStale && now.evidenceStale + ? `evidence for ${now.agentId} aged past the ${now.maxEvidenceAgeSeconds}s limit for this consequence` + : `trust for ${now.agentId} moved from ${was.trust} to ${now.trust}` + }); + } + } + return changes; +} + +export { agentTrustNow }; diff --git a/packages/pctr/src/probe.mjs b/packages/pctr/src/probe.mjs new file mode 100644 index 0000000..4f4ac13 --- /dev/null +++ b/packages/pctr/src/probe.mjs @@ -0,0 +1,69 @@ +import { execFile } from 'node:child_process'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { previewConsequence } from './twin.mjs'; + +// A probe measures what an action would actually affect, instead of trusting a number +// declared in pctr.json. A probe MUST be read-only: a dry run, a COUNT, a plan. PCTR +// runs it before anything is authorized, so a probe with side effects defeats the point. + +const PROBE_TIMEOUT_MS = 10_000; +const MEASURABLE = ['recordsAffected', 'amount', 'connectedWorkflows', 'dataClass', 'reversible', 'severity']; + +export async function runProbe(spec, context, { cwd = process.cwd(), timeoutMs = PROBE_TIMEOUT_MS } = {}) { + if (!spec) return { ok: false, skipped: true, fields: {} }; + const probe = typeof spec === 'string' ? { module: spec } : spec; + try { + const raw = probe.command + ? await runCommand(probe.command, probe.args ?? [], context, { cwd, timeoutMs }) + : await runModule(probe.module, context, { cwd }); + const fields = Object.fromEntries(Object.entries(raw ?? {}).filter(([k]) => MEASURABLE.includes(k))); + if (!Object.keys(fields).length) { + return { ok: false, fields: {}, error: `probe returned no measurable fields (expected one of: ${MEASURABLE.join(', ')})` }; + } + return { ok: true, fields, source: probe.command ?? probe.module }; + } catch (error) { + // A failing probe must never quietly become "no consequence". It downgrades to + // declared values and says so. + return { ok: false, fields: {}, error: error.message ?? String(error) }; + } +} + +async function runModule(modulePath, context, { cwd }) { + const resolved = pathToFileURL(path.resolve(cwd, modulePath)).href; + const mod = await import(resolved); + const fn = mod.default ?? mod.probe; + if (typeof fn !== 'function') throw new Error(`${modulePath} does not export a probe function`); + return await fn(context); +} + +function runCommand(command, args, context, { cwd, timeoutMs }) { + return new Promise((resolve, reject) => { + const child = execFile(command, args, { + cwd, timeout: timeoutMs, maxBuffer: 1024 * 1024, + env: { ...process.env, PCTR_ACTION: context.action, PCTR_TARGET: context.target ?? '', PCTR_PARAMS: JSON.stringify(context.params ?? {}) } + }, (error, stdout) => { + if (error) return reject(new Error(`probe command failed: ${error.message.split('\n')[0]}`)); + try { resolve(JSON.parse(stdout)); } + catch { reject(new Error(`probe command did not return JSON: ${String(stdout).slice(0, 80)}`)); } + }); + child.on('error', reject); + }); +} + +// The Consequence Twin, with measured values where a probe exists and declared values +// everywhere else. The result always says which is which. +export async function previewMeasured(graph, action, params = {}, { probes, cwd = process.cwd(), target } = {}) { + const spec = (probes ?? graph.manifest?.probes ?? {})[action]; + const result = await runProbe(spec, { action, target, params }, { cwd }); + const preview = previewConsequence(graph, action, { ...params, ...result.fields }); + return { + ...preview, + measured: result.ok, + measuredFields: Object.keys(result.fields), + probe: spec ? { source: result.source ?? (typeof spec === 'string' ? spec : spec.command), ok: result.ok, error: result.error ?? null } : null, + provenance: Object.fromEntries( + ['recordsAffected', 'amount', 'connectedWorkflows'].map((f) => [f, result.fields[f] !== undefined ? 'measured' : 'declared']) + ) + }; +} diff --git a/packages/pctr/src/protect.mjs b/packages/pctr/src/protect.mjs new file mode 100644 index 0000000..0bba845 --- /dev/null +++ b/packages/pctr/src/protect.mjs @@ -0,0 +1,136 @@ +import { previewConsequence, consequenceChanged } from './twin.mjs'; +import { resolveRoute } from './router.mjs'; +import { issueAuthority, verifyAuthority, createReplayStore } from './authority.mjs'; +import { createBoundary } from './boundary.mjs'; +import { issueReceipt } from './receipt.mjs'; +import { createTimeline } from './timeline.mjs'; +import { requiresHumanApproval } from './trust.mjs'; +import { trustDelta } from './observe.mjs'; + +// The Category King loop, executed end to end: +// PREVIEW -> ROUTE -> AUTHORIZE -> ENFORCE -> RECEIPT, with a replayable timeline. + +// Async because a real effect boundary is out of process: enforcement is I/O. +export async function protect(graph, rawRequest, options = {}) { + const request = { principal: graph.principal, ...rawRequest }; + const { + objective = null, approval = null, execute = null, clock, + replayStore = createReplayStore(), timeline = createTimeline({ objective, clock }), priorReceiptHash = null, + boundary = createBoundary({ replayStore, publicKey: options.publicKey, trustedKeyIds: options.trustedKeyIds }), + keyPair + } = options; + const t = timeline; + const policy = { ...(graph.manifest.policy ?? {}), ...(options.policy ?? {}) }; + + // A caller may hand us a timeline that is already running; state the objective once. + const started = t.last('AGENT_STARTED') + ?? t.record('AGENT_STARTED', { objective }, { subject: request.agent ?? graph.principal }); + const proposed = t.record('ACTION_PROPOSED', { action: request.action, ...request.params }, { subject: request.agent ?? null, because: [started.id] }); + + // PREVIEW — what will this cause? A caller that has already measured the consequence + // with a probe passes it in; otherwise it is computed from the graph. + const preview = options.preview ?? previewConsequence(graph, request.action, request.params ?? {}); + const detected = t.record('CONSEQUENCE_DETECTED', + { consequence: preview.consequence, severity: preview.severity, reversible: preview.reversible, blastRadius: preview.blastRadius.band }, + { because: [proposed.id] }); + + // ROUTE — which trustworthy path may get there? + const route = resolveRoute(graph, request.action, { policy, severity: preview.severity, target: request.target, at: options.at }); + if (!route.selected) { + const reason = route.candidates.length + ? route.candidates[0].rejections.map((r) => r.message).join('; ') + : `no agent in this graph can reach ${request.action}`; + const denied = t.record('EXECUTION_DENIED', { reason, failures: route.candidates.flatMap((c) => c.rejections) }, { because: [detected.id] }); + return finish({ t, request, preview, route: null, authority: null, + verification: { decision: 'EXECUTION_DENIED', failures: [{ code: 'NO_ADMISSIBLE_ROUTE', message: reason }] }, + result: null, policy, priorReceiptHash, deniedAt: denied.id }); + } + // If this timeline already rode a route for this action, say what changed and why the + // old one no longer holds, before recording the replacement. + const previous = [...t.events].reverse().find((e) => e.event === 'ROUTE_SELECTED' && e.detail.action === request.action); + const causes = [detected.id]; + if (previous) { + // Compare the agents that carried the previous route against their state *now* — + // otherwise a reroute hides the very trust change that caused it. + const priorRouteNow = route.candidates.find((c) => c.routeId === previous.detail.routeId)?.trustStates ?? []; + const currentStates = [...priorRouteNow, ...route.selected.trustStates]; + for (const change of trustDelta(previous.detail.trustStates, currentStates)) { + causes.push(t.record('TRUST_CHANGED', change, { subject: change.agentId, because: [detected.id] }).id); + } + if (previous.detail.routeId !== route.selected.routeId) { + const stale = route.candidates.find((c) => c.routeId === previous.detail.routeId); + causes.push(t.record('ROUTE_INVALIDATED', { + routeId: previous.detail.routeId, + reason: stale?.rejections.length + ? stale.rejections.map((x) => x.message).join('; ') + : 'a more trustworthy admissible route became available', + policy: policyRef(policy) + }, { because: [previous.id, detected.id] }).id); + } + } + const selected = t.record('ROUTE_SELECTED', + { action: request.action, routeId: route.selected.routeId, effectiveTrust: route.selected.effectiveTrust, + rejected: route.candidates.length - route.admissible.length, trustStates: route.selected.trustStates }, + { because: causes }); + + // AUTHORIZE — human approval first where the consequence demands it. + const needsApproval = requiresHumanApproval(preview.severity, policy) || + (policy.approvalThresholds?.amount != null && Number(request.params?.amount ?? 0) >= policy.approvalThresholds.amount); + if (needsApproval && !approval) { + const reason = `policy requires human approval for ${preview.severity} consequences`; + const denied = t.record('EXECUTION_DENIED', { reason, policy: policyRef(policy) }, { because: [detected.id, selected.id] }); + return finish({ t, request, preview, route: route.selected, authority: null, keyPair, + verification: { decision: 'EXECUTION_DENIED', failures: [{ code: 'APPROVAL_REQUIRED', message: reason }] }, + result: null, policy, priorReceiptHash, deniedAt: denied.id }); + } + + const hops = route.selected.agents; + for (let i = 1; i < hops.length; i++) { + t.record('AGENT_DELEGATED', { to: hops[i], forAction: request.action }, { subject: hops[i - 1], because: [selected.id] }); + } + const tool = route.selected.path.at(-2); + if (tool) t.record('CAPABILITY_DISCOVERED', { tool, actions: [request.action] }, { subject: hops.at(-1) ?? null, because: [selected.id] }); + + const requested = t.record('AUTHORITY_REQUESTED', { action: request.action }, { because: [selected.id] }); + const authority = issueAuthority({ + principal: graph.principal, delegator: route.selected.agents.at(-2) ?? null, session: t.runId, + action: request.action, target: request.target ?? request.action, params: request.params ?? {}, + constraints: { ...(options.constraints ?? {}), requiresApproval: Boolean(needsApproval), + materialParams: options.materialParams ?? Object.keys(request.params ?? {}) }, + policyVersion: policyRef(policy), consequence: preview.consequence, route: route.selected, + validForSeconds: options.validForSeconds ?? 300, issuedAt: options.at, + ...(keyPair ? { keyPair } : {}) + }); + const issued = t.record('AUTHORITY_ISSUED', { bindingHash: authority.bindingHash, expiresAt: authority.expiresAt }, { because: [requested.id] }); + + // ENFORCE — the effect boundary verifies independently of the requesting agent. + t.record('EXECUTION_REQUESTED', { action: request.action }, { subject: request.agent ?? null, because: [issued.id] }); + const execution = { action: request.action, target: request.target ?? request.action, params: request.params ?? {}, principal: graph.principal, approval }; + const verification = await boundary.verify(authority, execution, { now: options.at }); + if (!verification.allowed) { + const denied = t.record('EXECUTION_DENIED', { failures: verification.failures, reason: verification.failures.map((f) => f.message).join('; ') }, { because: [issued.id] }); + return finish({ t, request, preview, route: route.selected, authority, verification, result: null, policy, priorReceiptHash, deniedAt: denied.id, keyPair }); + } + const allowed = t.record('EXECUTION_ALLOWED', { bindingHash: authority.bindingHash }, { because: [issued.id] }); + + const result = execute + ? { status: 'SUCCEEDED', output: execute(execution), executedAt: options.at ?? new Date().toISOString() } + : { status: 'SIMULATED', output: null, executedAt: options.at ?? new Date().toISOString() }; + t.record('EXECUTION_COMPLETED', { action: request.action, status: result.status }, { because: [allowed.id] }); + + return finish({ t, request, preview, route: route.selected, authority, verification, result, policy, priorReceiptHash, routeResult: route, keyPair }); +} + +function finish({ t, request, preview, route, authority, verification, result, policy, priorReceiptHash, routeResult, deniedAt, keyPair }) { + const receipt = issueReceipt({ request, preview, route, authority, verification, result, policyVersion: policyRef(policy), priorReceiptHash, ...(keyPair ? { keyPair } : {}) }); + t.record('RECEIPT_ISSUED', { receiptId: receipt.receiptId, receiptHash: receipt.receiptHash }, + { because: deniedAt ? [deniedAt] : [t.last('EXECUTION_COMPLETED')?.id].filter(Boolean) }); + return { allowed: Boolean(verification?.allowed), preview, route, routeResult, authority, verification, result, receipt, timeline: t }; +} + +const policyRef = (policy) => policy.version ?? 'local-v1'; + +// Simulation runs the whole loop without ever executing an effect. +export const simulate = (graph, request, options = {}) => protect(graph, request, { ...options, execute: null }); +export { verifyAuthority }; +export { consequenceChanged }; diff --git a/packages/pctr/src/receipt.mjs b/packages/pctr/src/receipt.mjs new file mode 100644 index 0000000..473322f --- /dev/null +++ b/packages/pctr/src/receipt.mjs @@ -0,0 +1,74 @@ +import crypto from 'node:crypto'; +import { hashObj } from '../../../src/util.mjs'; +import { defaultKeyPair, signHash, verifyHash, exportPublic, keyIdFor } from './keys.mjs'; + +// A receipt is not a log line. It is verifiable evidence of what was requested, who +// authorized it, what was bound, what executed, and what resulted. Signing is symmetric +// (HMAC) today: that makes a receipt tamper-evident, not third-party verifiable. Anyone +// holding the signing key can also mint one — asymmetric signing is still to do. + +export function issueReceipt({ + request, preview, route, authority, verification, result, + policyVersion = 'local-v1', priorReceiptHash = null, keyPair = defaultKeyPair(), + issuedAt = new Date().toISOString() +}) { + const payload = { + type: 'PCTRExecutionReceipt', version: 1, + receiptId: `rcpt-${crypto.randomUUID()}`, + requested: { action: request.action, target: request.target, params: request.params ?? {} }, + requestedBy: request.agent ?? null, + principal: authority?.principal ?? request.principal ?? null, + delegator: authority?.delegator ?? null, + routeSelected: route ? { routeId: route.routeId, routeHash: route.routeHash, effectiveTrust: route.effectiveTrust, agents: route.agents } : null, + consequence: preview ? { class: preview.consequence, severity: preview.severity, reversible: preview.reversible, blastRadius: preview.blastRadius } : null, + authorityBound: authority ? { bindingHash: authority.bindingHash, materialParams: authority.materialParams, constraints: authority.constraints, expiresAt: authority.expiresAt, nonce: authority.nonce, signedBy: authority.keyId ?? null } : null, + verifier: { boundary: verification?.boundary ?? 'pctr.effect-boundary', decision: verification?.decision ?? 'EXECUTION_DENIED', failures: verification?.failures ?? [], signerVerified: verification?.signerVerified ?? false }, + executed: result ? { status: result.status, output: result.output ?? null, executedAt: result.executedAt ?? issuedAt } : null, + policyVersion, issuedAt, priorReceiptHash, + keyId: keyPair.keyId ?? keyIdFor(keyPair.publicKey) + }; + const receiptHash = hashObj(payload); + return { ...payload, receiptHash, signature: signHash(receiptHash, keyPair), signerPublicKey: exportPublic(keyPair.publicKey) }; +} + +export function verifyReceipt(receipt, { publicKey, trustedKeyIds, priorReceiptHash = undefined } = {}) { + const failures = []; + const { receiptHash, signature, signerPublicKey, ...payload } = receipt ?? {}; + if (!receipt) return { valid: false, signerVerified: false, failures: [{ code: 'RECEIPT_MISSING', message: 'no receipt provided' }] }; + if (hashObj(payload) !== receiptHash) failures.push({ code: 'RECEIPT_HASH_MISMATCH', message: 'receipt contents were altered after signing' }); + + // A third party verifies with a key they already hold. The embedded key can only + // establish internal consistency, so verification says which of the two happened. + const key = publicKey ?? signerPublicKey; + const signerVerified = Boolean(publicKey) || (Array.isArray(trustedKeyIds) && trustedKeyIds.includes(payload.keyId)); + if (!key) failures.push({ code: 'SIGNATURE_INVALID', message: 'receipt carries no verification key' }); + else if (!verifyHash(receiptHash, signature, key)) failures.push({ code: 'SIGNATURE_INVALID', message: 'receipt signature does not verify' }); + else if (signature?.keyId !== payload.keyId) failures.push({ code: 'SIGNER_MISMATCH', message: 'signature key id does not match the key id inside the receipt' }); + if (Array.isArray(trustedKeyIds) && !trustedKeyIds.includes(payload.keyId)) { + failures.push({ code: 'UNTRUSTED_SIGNER', message: `receipt was signed by ${payload.keyId}, which is not a trusted signer` }); + } + if (priorReceiptHash !== undefined && payload.priorReceiptHash !== priorReceiptHash) { + failures.push({ code: 'CHAIN_BROKEN', message: 'receipt does not chain to the expected prior receipt' }); + } + if (payload.executed && payload.verifier?.decision !== 'EXECUTION_ALLOWED') { + failures.push({ code: 'EXECUTED_WITHOUT_AUTHORITY', message: 'receipt records an execution that was not allowed' }); + } + return { + valid: failures.length === 0, receiptId: payload.receiptId, signerVerified, keyId: payload.keyId, failures, + warnings: failures.length === 0 && !signerVerified + ? [{ code: 'UNPINNED_KEY', message: 'signature is internally consistent, but the signer was not pinned; pass publicKey or trustedKeyIds to verify who signed it' }] + : [] + }; +} + +// Receipts chain, so a missing or reordered receipt is detectable. +export function verifyReceiptChain(receipts, opts = {}) { + const failures = []; + let prior = null; + for (const r of receipts) { + const res = verifyReceipt(r, { ...opts, priorReceiptHash: prior }); + if (!res.valid) failures.push({ receiptId: r.receiptId, failures: res.failures }); + prior = r.receiptHash; + } + return { valid: failures.length === 0, length: receipts.length, failures }; +} diff --git a/packages/pctr/src/render.mjs b/packages/pctr/src/render.mjs new file mode 100644 index 0000000..b0b3550 --- /dev/null +++ b/packages/pctr/src/render.mjs @@ -0,0 +1,141 @@ +import { protectedActions, pathsToAction, summarize } from './graph.mjs'; +import { replay as replayTimeline, describe } from './timeline.mjs'; + +// Plain English first. Machine-readable output is opt-in via --json. +const ESC = String.fromCharCode(27); +const useColor = () => process.stdout.isTTY && !process.env.NO_COLOR; +const c = (code) => (s) => (useColor() ? `${ESC}[${code}m${s}${ESC}[0m` : String(s)); +export const dim = c('2'); export const bold = c('1'); +export const red = c('31'); export const green = c('32'); export const yellow = c('33'); export const cyan = c('36'); + +const SEV_COLOR = { CRITICAL: red, HIGH: yellow, MEDIUM: cyan, LOW: dim }; +export const sev = (s) => (SEV_COLOR[s] ?? dim)(s); +export const heading = (text) => `\n${bold(text.toUpperCase())}\n`; +export const field = (label, value, width = 22) => `${label.padEnd(width)}${value}`; +export const chain = (ids) => ids.join(`\n${dim(' |')}\n${dim(' v')}\n`); + +export function renderScan(graph) { + const s = summarize(graph); + const out = [heading('PCTR'), 'Scanning your agents...', '']; + out.push(field('Agents found', String(s.agents))); + out.push(field('Tools found', String(s.tools))); + out.push(field('External systems', String(s.externalSystems))); + out.push(field('Potential actions', String(s.actions))); + out.push('', bold('Protected consequences'), ''); + for (const level of ['CRITICAL', 'HIGH', 'MEDIUM']) out.push(field(sev(level), String(s.bySeverity[level]))); + const top = protectedActions(graph)[0]; + if (top) { + out.push('', bold('Highest priority:'), '', top.id, '', bold('Route:'), ''); + out.push(chain(pathsToAction(graph, top.id)[0] ?? [])); + out.push('', bold('Problem:'), '', + `The final action can cause "${top.label}"${top.reversible ? '' : ' irreversibly'} without independent execution authority.`, + '', bold('Recommended:'), '', `Add TTP authority verification before ${top.id}.`); + } else { + out.push('', 'No protected consequences found. Nothing here can cause an irreversible change.'); + } + return out.join('\n'); +} + +export function renderPreview(p) { + // Say where each number came from: a measured value and a value someone typed into + // pctr.json deserve different confidence. + const mark = (name) => (p.provenance?.[name] === 'measured' ? green(' (measured)') : p.provenance ? dim(' (declared)') : ''); + const out = [heading('consequence preview')]; + out.push(field('Action', p.action)); + out.push(field('Causes', p.label)); + if (p.recordsAffected != null) out.push(field('Records affected', `${p.recordsAffected}${mark('recordsAffected')}`)); + if (p.financialExposure != null) out.push(field('Financial exposure', `$${p.financialExposure}${mark('amount')}`)); + out.push(field('Reversible', p.reversible ? green('YES') : red('NO'))); + out.push(field('Connected workflows', String(p.connectedWorkflows))); + out.push(field('Blast radius', `${p.blastRadius.band} (${p.blastRadius.score}/100)`)); + out.push(field('Routes that reach it', String(p.routesThatCanReachIt))); + out.push(field('Risk', sev(p.severity))); + if (p.probe && !p.probe.ok) out.push('', yellow(`Probe did not run: ${p.probe.error}`), dim('Falling back to declared values.')); + out.push('', bold('Recommended'), '', ...p.recommendations.map((r) => `- ${r}`)); + return out.join('\n'); +} + +export function renderRoute(r) { + const out = []; + if (!r.selected) { + out.push(heading('no admissible route')); + out.push(`Nothing can reach ${bold(r.action)} under current trust and policy.`, ''); + for (const cand of r.candidates) { + out.push(dim(cand.routeId)); + for (const rej of cand.rejections) out.push(` ${red('x')} ${rej.message}`); + out.push(''); + } + return out.join('\n'); + } + out.push(heading('route selected')); + out.push(chain(r.selected.path)); + out.push('', field('Effective trust', `${r.selected.effectiveTrust} (${r.trustRequired} required for ${sev(r.severity)})`)); + out.push(field('Hops', String(r.selected.hops))); + if (r.requiresApproval) out.push(field('Human approval', yellow('REQUIRED'))); + const rejected = r.candidates.filter((x) => !x.admissible); + if (rejected.length) { + out.push('', bold('Rejected routes'), ''); + for (const cand of rejected) { + out.push(dim(cand.routeId)); + for (const rej of cand.rejections) out.push(` ${red('x')} ${rej.message}`); + } + } + return out.join('\n'); +} + +export function renderGraph(graph) { + const out = [heading('trust graph')]; + out.push(graph.principal); + for (const a of [...graph.nodes.values()].filter((n) => n.type === 'agent')) { + const delegated = graph.edges.filter((e) => e.from === a.id && e.kind === 'delegates').map((e) => e.to); + const tools = graph.edges.filter((e) => e.from === a.id && e.kind === 'uses').map((e) => e.to); + out.push(` |- ${bold(a.id)} ${dim(`[${a.framework}] trust ${a.trust}`)}`); + for (const d of delegated) out.push(` ${dim('delegates ->')} ${d}`); + for (const t of tools) { + out.push(` ${dim('uses ->')} ${t}`); + for (const act of graph.edges.filter((e) => e.from === t && e.kind === 'performs').map((e) => e.to)) { + const node = graph.nodes.get(act); + out.push(` ${node.protected ? red('!') : dim('.')} ${act} ${dim(`-> ${node.label}`)} ${node.protected ? sev(node.severity) : ''}`); + } + } + } + out.push('', dim('! = protected consequence: must not execute on credential possession alone')); + return out.join('\n'); +} + +export function renderTimeline(timeline) { + const out = [heading('agent time machine'), dim(`run ${timeline.runId}`), '']; + for (const e of replayTimeline(timeline)) out.push(`${dim(e.at.slice(11, 19))} ${e.line}`); + out.push('', dim('Ask why with: pctr explain ')); + return out.join('\n'); +} + +export function renderWhy(w) { + if (!w.found) return w.explanation; + const out = [heading(w.question)]; + out.push(w.answer, '', bold('Because'), ''); + out.push(...w.because.map((b) => `- ${b}`)); + if (w.policy) out.push('', field('Policy', w.policy)); + return out.join('\n'); +} + +export function renderReceipt(receipt, verification) { + const out = [heading('execution receipt')]; + out.push(field('Receipt', receipt.receiptId)); + out.push(field('Requested', `${receipt.requested.action} on ${receipt.requested.target}`)); + out.push(field('Principal', String(receipt.principal))); + out.push(field('Delegated by', String(receipt.delegator ?? '-'))); + out.push(field('Route', receipt.routeSelected?.routeId ?? '-')); + out.push(field('Consequence', receipt.consequence ? `${receipt.consequence.class} (${sev(receipt.consequence.severity)})` : '-')); + out.push(field('Authority bound to', receipt.authorityBound ? JSON.stringify(receipt.authorityBound.materialParams) : '-')); + out.push(field('Verified by', receipt.verifier.boundary)); + out.push(field('Decision', receipt.verifier.decision === 'EXECUTION_ALLOWED' ? green(receipt.verifier.decision) : red(receipt.verifier.decision))); + for (const f of receipt.verifier.failures) out.push(` ${red('x')} ${f.message}`); + out.push(field('Executed', receipt.executed ? `${receipt.executed.status} at ${receipt.executed.executedAt}` : 'NOT EXECUTED')); + out.push(field('Policy version', receipt.policyVersion)); + out.push(field('Receipt hash', dim(receipt.receiptHash))); + if (verification) out.push('', verification.valid ? green('Receipt verifies.') : red(`Receipt INVALID: ${verification.failures.map((f) => f.message).join('; ')}`)); + return out.join('\n'); +} + +export { describe }; diff --git a/packages/pctr/src/router.mjs b/packages/pctr/src/router.mjs new file mode 100644 index 0000000..e758bde --- /dev/null +++ b/packages/pctr/src/router.mjs @@ -0,0 +1,108 @@ +import { pathsToAction } from './graph.mjs'; +import { agentTrustNow, meetsThreshold, TRUST_REQUIRED, requiresHumanApproval } from './trust.mjs'; +import { verify_trust_route } from './ttp.mjs'; + +// Trust Routing is not shortest-path routing. Admissibility first; optimization only +// among routes that are already authorized, trustworthy and consequence-compatible. +// A security constraint is never traded away for a cheaper or faster route. + +const holdsAuthority = (agent, actionId) => + (agent.authority ?? []).some((a) => a === '*' || a === actionId || (a.endsWith('.*') && actionId.startsWith(a.slice(0, -1)))); + +export function resolveRoute(graph, actionId, options = {}) { + const action = graph.nodes.get(actionId); + if (!action || action.type !== 'action') { + return { selected: null, candidates: [], error: `Unknown action: ${actionId}` }; + } + const policy = { ...(graph.manifest.policy ?? {}), ...(options.policy ?? {}) }; + const severity = options.severity ?? action.severity; + const at = options.at ?? new Date().toISOString(); + + const candidates = pathsToAction(graph, actionId).map((path) => { + const agents = path.filter((id) => graph.nodes.get(id)?.type === 'agent').map((id) => graph.nodes.get(id)); + const rejections = []; + const trustStates = agents.map((a) => agentTrustNow(a, { severity, at, decayConstant: policy.decayConstant })); + + // 1. remove unauthorized routes + for (const a of agents) { + if (!holdsAuthority(a, actionId)) { + rejections.push({ code: 'INSUFFICIENT_AUTHORITY', agent: a.id, + message: `${a.id} does not hold authority for ${actionId}` }); + } + } + // 2. remove untrustworthy routes (including stale evidence) + for (const t of trustStates) { + if (t.evidenceStale) { + rejections.push({ code: 'STALE_EVIDENCE', agent: t.agentId, + message: `${t.agentId} evidence is ${t.evidenceAgeSeconds}s old; ${severity} actions require evidence under ${t.maxEvidenceAgeSeconds}s` }); + } + } + const depth = Math.max(0, agents.length - 1); + const perHop = policy.decayPerHop ?? 0.05; + const effectiveTrust = trustStates.length + ? Number(Math.max(0, Math.min(...trustStates.map((t) => t.trust)) - perHop * depth).toFixed(4)) + : 0; + if (!meetsThreshold(effectiveTrust, severity)) { + rejections.push({ code: 'TRUST_BELOW_THRESHOLD', + message: `effective trust ${effectiveTrust} is below the ${TRUST_REQUIRED[severity]} required for ${severity} consequences` }); + } + // 3. remove consequence-incompatible routes + const allowed = policy.jurisdictions?.[action.consequence]; + for (const a of agents) { + if (allowed && a.jurisdiction && !allowed.includes(a.jurisdiction)) { + rejections.push({ code: 'JURISDICTION_INCOMPATIBLE', agent: a.id, + message: `${a.id} operates in ${a.jurisdiction}; ${action.consequence} is limited to ${allowed.join(', ')}` }); + } + if (a.available === false) { + rejections.push({ code: 'AGENT_UNAVAILABLE', agent: a.id, message: `${a.id} is unavailable` }); + } + } + // 4. remove policy-invalid routes (protocol-level route check via TTP) + const ttp = verify_trust_route({ + routeId: path.join('>'), + hops: agents.map((a) => ({ subject: a.id, issuer: a.issuer ?? graph.principal, trustScore: a.trust ?? 0 })), + maxHops: policy.maxHops ?? 6, + decayPerHop: perHop, + minIntermediateTrust: policy.minIntermediateTrust ?? 0, + sourceDomain: policy.sourceDomain ?? 'local', + targetDomain: policy.targetDomain ?? 'local', + action: actionId, + resource: options.target ?? action.target ?? actionId, + routePolicy: policy.routePolicy + }); + for (const f of ttp.failureReasons) rejections.push({ code: f.code, message: f.message }); + + const latencyMs = agents.reduce((s, a) => s + (a.latencyMs ?? 0), 0); + const costUnits = agents.reduce((s, a) => s + (a.costUnits ?? 0), 0); + return { + routeId: path.join(' -> '), path, agents: agents.map((a) => a.id), hops: path.length, + effectiveTrust, trustStates, latencyMs, costUnits, + routeHash: ttp.routeHash, admissible: rejections.length === 0, rejections + }; + }); + + // 5. optimize only what survived + const admissible = candidates.filter((c) => c.admissible).sort((a, b) => + b.effectiveTrust - a.effectiveTrust || a.latencyMs - b.latencyMs || a.costUnits - b.costUnits || a.hops - b.hops); + + const selected = admissible[0] ?? null; + return { + action: actionId, severity, consequence: action.consequence, at, + selected, admissible, candidates, + requiresApproval: requiresHumanApproval(severity, policy), + trustRequired: TRUST_REQUIRED[severity] + }; +} + +// Authority MUST NOT silently expand during rerouting: a replacement route may never +// be admitted on weaker grounds than the route it replaces. +export function reroute(graph, actionId, previous, options = {}) { + const next = resolveRoute(graph, actionId, options); + if (previous?.selected && next.selected) { + if (next.severity !== previous.severity || next.trustRequired < previous.trustRequired) { + return { ...next, selected: null, expansionBlocked: true, + reason: 'replacement route would have required weaker authority than the route it replaces' }; + } + } + return { ...next, replaced: previous?.selected?.routeId ?? null }; +} diff --git a/packages/pctr/src/store.mjs b/packages/pctr/src/store.mjs new file mode 100644 index 0000000..36227d2 --- /dev/null +++ b/packages/pctr/src/store.mjs @@ -0,0 +1,49 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +// Everything PCTR learns locally lives in ./.pctr — no account, no network. +export const dir = (cwd = process.cwd()) => path.join(cwd, '.pctr'); +const ensure = (p) => { fs.mkdirSync(p, { recursive: true }); return p; }; + +export const manifestPath = (cwd = process.cwd()) => path.join(cwd, 'pctr.json'); + +export function readManifest(cwd = process.cwd()) { + const p = manifestPath(cwd); + if (!fs.existsSync(p)) return null; + return JSON.parse(fs.readFileSync(p, 'utf8')); +} +export function writeManifest(manifest, cwd = process.cwd()) { + fs.writeFileSync(manifestPath(cwd), `${JSON.stringify(manifest, null, 2)}\n`); + return manifestPath(cwd); +} + +export function saveRun(timeline, cwd = process.cwd()) { + const p = path.join(ensure(path.join(dir(cwd), 'runs')), `${timeline.runId}.json`); + fs.writeFileSync(p, `${JSON.stringify(timeline.toJSON ? timeline.toJSON() : timeline, null, 2)}\n`); + return p; +} +export function listRuns(cwd = process.cwd()) { + const p = path.join(dir(cwd), 'runs'); + if (!fs.existsSync(p)) return []; + return fs.readdirSync(p).filter((f) => f.endsWith('.json')) + .map((f) => ({ runId: f.replace(/\.json$/, ''), file: path.join(p, f), mtime: fs.statSync(path.join(p, f)).mtimeMs })) + .sort((a, b) => b.mtime - a.mtime); +} +export function loadRun(runId, cwd = process.cwd()) { + const runs = listRuns(cwd); + const hit = runId ? runs.find((r) => r.runId === runId) : runs[0]; + return hit ? JSON.parse(fs.readFileSync(hit.file, 'utf8')) : null; +} + +export function saveReceipt(receipt, cwd = process.cwd()) { + const p = path.join(ensure(path.join(dir(cwd), 'receipts')), `${receipt.receiptId}.json`); + fs.writeFileSync(p, `${JSON.stringify(receipt, null, 2)}\n`); + return p; +} +export function listReceipts(cwd = process.cwd()) { + const p = path.join(dir(cwd), 'receipts'); + if (!fs.existsSync(p)) return []; + return fs.readdirSync(p).filter((f) => f.endsWith('.json')) + .map((f) => JSON.parse(fs.readFileSync(path.join(p, f), 'utf8'))) + .sort((a, b) => a.issuedAt.localeCompare(b.issuedAt)); +} diff --git a/packages/pctr/src/timeline.mjs b/packages/pctr/src/timeline.mjs new file mode 100644 index 0000000..379d3ef --- /dev/null +++ b/packages/pctr/src/timeline.mjs @@ -0,0 +1,135 @@ +import crypto from 'node:crypto'; +import { isCanonicalEvent } from './events.mjs'; + +// AGENT TIME MACHINE — replay exactly why your AI did what it did. +// Every event records what happened and which earlier events caused it, so "why" +// is answered deterministically from evidence rather than re-narrated by a model. + +export function createTimeline({ runId = `run-${crypto.randomUUID().slice(0, 8)}`, objective = null, clock } = {}) { + const events = []; + const now = clock ?? (() => new Date().toISOString()); + const api = { + runId, objective, events, + record(event, detail = {}, { subject = null, because = [] } = {}) { + if (!isCanonicalEvent(event)) throw new Error(`Not a canonical PCTR event: ${event}`); + const entry = { seq: events.length, id: `e${events.length}`, at: now(), event, subject, detail, because }; + events.push(entry); + return entry; + }, + last: (event) => [...events].reverse().find((e) => e.event === event) ?? null, + toJSON: () => ({ runId, objective, events }) + }; + return api; +} + +export const fromJSON = (data) => { + const t = createTimeline({ runId: data.runId, objective: data.objective }); + t.events.push(...(data.events ?? [])); + return t; +}; + +// REPLAY — the timeline as it happened. +export function replay(timeline) { + return timeline.events.map((e) => ({ at: e.at, event: e.event, line: describe(e), id: e.id })); +} + +// WHY — deterministic explanation built from the recorded causal chain. +export function why(timeline, eventIdOrName) { + const target = timeline.events.find((e) => e.id === eventIdOrName) ?? + [...timeline.events].reverse().find((e) => e.event === eventIdOrName); + if (!target) return { found: false, question: eventIdOrName, explanation: `No event matching "${eventIdOrName}" in this run.` }; + + const chain = []; + const visit = (event, depth = 0) => { + if (depth > 8) return; + for (const id of event.because ?? []) { + const cause = timeline.events.find((e) => e.id === id); + if (cause && !chain.some((c) => c.id === cause.id)) { chain.push(cause); visit(cause, depth + 1); } + } + }; + visit(target); + const reasons = chain.sort((a, b) => a.seq - b.seq).map(describe); + return { + found: true, + question: questionFor(target), + answer: target.detail.reason ?? answerFor(target), + because: reasons.length ? reasons : ['This was the first event in the run; nothing preceded it.'], + policy: target.detail.policy ?? null + }; +} + +// FORK + SIMULATE — replay the run with changed inputs, without executing anything. +export function fork(timeline, { upTo = null } = {}) { + const cut = upTo ? timeline.events.findIndex((e) => e.id === upTo) + 1 : timeline.events.length; + const forked = createTimeline({ runId: `${timeline.runId}-fork`, objective: timeline.objective }); + forked.events.push(...timeline.events.slice(0, cut).map((e) => ({ ...e }))); + return forked; +} + +// COMPARE — what differs between two runs, and where they diverged. +export function compare(a, b) { + const rows = []; + const max = Math.max(a.events.length, b.events.length); + let divergedAt = null; + for (let i = 0; i < max; i++) { + const left = a.events[i]; const right = b.events[i]; + const same = describe(left ?? {}) === describe(right ?? {}); + if (!same && divergedAt === null) divergedAt = i; + rows.push({ seq: i, left: left ? describe(left) : null, right: right ? describe(right) : null, same }); + } + return { divergedAt, rows, sameOutcome: outcomeOf(a) === outcomeOf(b), outcomes: [outcomeOf(a), outcomeOf(b)] }; +} + +const outcomeOf = (t) => [...t.events].reverse().find((e) => + ['EXECUTION_COMPLETED', 'EXECUTION_ALLOWED', 'EXECUTION_DENIED'].includes(e.event))?.event ?? 'NO_OUTCOME'; + +const QUESTIONS = { + EXECUTION_DENIED: 'WHY WAS THIS EXECUTION DENIED?', + EXECUTION_ALLOWED: 'WHY WAS THIS EXECUTION ALLOWED?', + EXECUTION_COMPLETED: 'WHY DID THIS ACTION EXECUTE?', + ROUTE_SELECTED: 'WHY WAS THIS ROUTE SELECTED?', + ROUTE_INVALIDATED: 'WHY WAS THE ROUTE INVALIDATED?', + AUTHORITY_ISSUED: 'WHY WAS AUTHORITY ISSUED?', + CONSEQUENCE_DETECTED: 'WHY IS THIS A PROTECTED CONSEQUENCE?', + TRUST_CHANGED: 'WHY DID TRUST CHANGE?', + RECEIPT_ISSUED: 'WHY WAS THIS RECEIPT ISSUED?' +}; +const questionFor = (e) => QUESTIONS[e.event] ?? `WHY: ${describe(e).toUpperCase()}?`; + +function answerFor(e) { + const d = e.detail ?? {}; + switch (e.event) { + case 'EXECUTION_ALLOWED': + return `Authority ${String(d.bindingHash ?? '').slice(0, 19)}… bound this exact execution, and the effect boundary verified it independently of the agent that requested it.`; + case 'ROUTE_SELECTED': + return `${d.routeId} was the most trustworthy admissible route; ${d.rejected ?? 0} candidate route(s) were rejected before optimization.`; + case 'AUTHORITY_ISSUED': + return `Authority was issued for this execution and expires at ${d.expiresAt}.`; + case 'CONSEQUENCE_DETECTED': + return `This action can cause ${d.consequence}, rated ${d.severity}${d.reversible === false ? ' and irreversible' : ''}.`; + default: return describe(e); + } +} + +export function describe(e) { + const d = e.detail ?? {}; + switch (e.event) { + case 'AGENT_DISCOVERED': return `Agent discovered: ${e.subject}`; + case 'AGENT_STARTED': return `Objective received${d.objective ? `: ${d.objective}` : ''}`; + case 'AGENT_DELEGATED': return `${e.subject} delegated to ${d.to}`; + case 'CAPABILITY_DISCOVERED': return `Capability discovered: ${d.tool ?? e.subject}`; + case 'ACTION_PROPOSED': return `Action proposed: ${d.action}${d.amount ? ` ($${d.amount})` : ''}`; + case 'CONSEQUENCE_DETECTED': return `Consequence detected: ${d.consequence} (${d.severity})`; + case 'TRUST_CHANGED': return `Trust changed: ${e.subject} ${d.from} -> ${d.to}`; + case 'ROUTE_SELECTED': return `Route selected: ${d.routeId}`; + case 'ROUTE_INVALIDATED': return `Route invalidated: ${d.routeId}`; + case 'AUTHORITY_REQUESTED': return `Authority requested for ${d.action}`; + case 'AUTHORITY_ISSUED': return `TTP authority issued (${String(d.bindingHash ?? '').slice(0, 19)}…)`; + case 'EXECUTION_REQUESTED': return `Execution requested: ${d.action}`; + case 'EXECUTION_ALLOWED': return `Effect boundary verified authority`; + case 'EXECUTION_DENIED': return `Execution denied: ${d.reason ?? (d.failures ?? []).map((f) => f.code).join(', ')}`; + case 'EXECUTION_COMPLETED': return `${d.action ?? 'Action'} executed`; + case 'RECEIPT_ISSUED': return `Receipt signed (${d.receiptId})`; + default: return `${e.event}${e.subject ? ` ${e.subject}` : ''}`; + } +} diff --git a/packages/pctr/src/trust.mjs b/packages/pctr/src/trust.mjs new file mode 100644 index 0000000..6afd2a5 --- /dev/null +++ b/packages/pctr/src/trust.mjs @@ -0,0 +1,40 @@ +import { apply_decay } from './ttp.mjs'; +import { severityRank } from './consequences.mjs'; + +// Trust is not permanent. Evidence ages, and aged evidence buys less authority. +export const TRUST_REQUIRED = { CRITICAL: 0.90, HIGH: 0.75, MEDIUM: 0.60, LOW: 0.0 }; +export const MAX_EVIDENCE_AGE_SECONDS = { CRITICAL: 300, HIGH: 900, MEDIUM: 3600, LOW: Infinity }; + +const RISK_TIER = { CRITICAL: 'high', HIGH: 'high', MEDIUM: 'medium', LOW: 'low' }; + +export function agentTrustNow(agent, { severity = 'MEDIUM', decayConstant = 0.00005, at = new Date().toISOString() } = {}) { + const decayed = apply_decay({ + initialTrust: agent.trust ?? 0, + decayConstant, + elapsedSeconds: agent.evidenceAgeSeconds ?? 0, + activitySignals: agent.activitySignals ?? [], + riskTier: RISK_TIER[severity] ?? 'low', + calculatedAt: at + }); + const maxAge = MAX_EVIDENCE_AGE_SECONDS[severity]; + return { + agentId: agent.id, + trust: Number(decayed.finalTrust.toFixed(4)), + declaredTrust: agent.trust ?? 0, + evidenceAgeSeconds: agent.evidenceAgeSeconds ?? 0, + evidenceStale: (agent.evidenceAgeSeconds ?? 0) > maxAge, + maxEvidenceAgeSeconds: maxAge + }; +} + +export const meetsThreshold = (trust, severity) => trust >= (TRUST_REQUIRED[severity] ?? 0); + +// A trust input changed materially enough to force route reevaluation. +export function trustChanged(before, after) { + return before.trust !== after.trust || before.evidenceStale !== after.evidenceStale; +} + +export const requiresHumanApproval = (severity, policy = {}) => + policy.requireApprovalAtOrAbove + ? severityRank(severity) >= severityRank(policy.requireApprovalAtOrAbove) + : severity === 'CRITICAL'; diff --git a/packages/pctr/src/ttp.mjs b/packages/pctr/src/ttp.mjs new file mode 100644 index 0000000..ecbad3a --- /dev/null +++ b/packages/pctr/src/ttp.mjs @@ -0,0 +1,3 @@ +// Single adapter point onto the TTP protocol primitives, so PCTR depends on TTP +// in exactly one place. In-repo this resolves by path; published it resolves by package. +export { apply_decay, verify_trust_route, generate_trust_proof } from '../../../src/index.mjs'; diff --git a/packages/pctr/src/twin.mjs b/packages/pctr/src/twin.mjs new file mode 100644 index 0000000..7dc37cf --- /dev/null +++ b/packages/pctr/src/twin.mjs @@ -0,0 +1,65 @@ +import { classifyAction, severityRank } from './consequences.mjs'; +import { outgoing, pathsToAction } from './graph.mjs'; + +// CONSEQUENCE TWIN — see what your AI is about to change before it changes it. +// git diff / terraform plan / EXPLAIN, for autonomous agents. + +export function previewConsequence(graph, actionId, params = {}) { + const node = graph.nodes.get(actionId); + const hints = { ...(node ?? {}), ...params }; + const c = classifyAction(actionId, hints); + const recordsAffected = params.recordsAffected ?? node?.recordsAffected ?? null; + const amount = params.amount ?? node?.amount ?? null; + const routes = pathsToAction(graph, actionId); + + const affectedSystems = [...new Set(routes.map((p) => p[p.length - 2]).filter(Boolean))]; + const affectedIdentities = [...new Set(routes.flatMap((p) => p.slice(0, -2)))]; + const connectedWorkflows = node?.connectedWorkflows ?? affectedSystems.length; + const downstream = outgoing(graph, actionId, 'triggers'); + + const blastRadius = computeBlastRadius({ severity: c.severity, recordsAffected, connectedWorkflows, routes: routes.length }); + + return { + action: actionId, + consequence: c.consequence, + label: c.label, + severity: c.severity, + reversible: c.reversible, + protected: c.protected, + recordsAffected, + financialExposure: amount, + dataExposure: c.consequence === 'SECRET_EXPOSED' || c.consequence === 'DATA_READ' ? (params.dataClass ?? 'unknown') : null, + affectedSystems, + affectedIdentities, + connectedWorkflows, + downstreamDependencies: downstream, + routesThatCanReachIt: routes.length, + blastRadius, + recommendations: recommend({ action: actionId, c, recordsAffected, amount, connectedWorkflows }) + }; +} + +function computeBlastRadius({ severity, recordsAffected, connectedWorkflows, routes }) { + let score = severityRank(severity) * 20; + if (recordsAffected) score += Math.min(40, Math.log10(recordsAffected + 1) * 12); + score += Math.min(20, connectedWorkflows * 4); + score += Math.min(20, routes * 4); + const value = Math.round(Math.min(100, score)); + return { score: value, band: value >= 75 ? 'WIDE' : value >= 45 ? 'MODERATE' : 'NARROW' }; +} + +function recommend({ c, recordsAffected, amount, connectedWorkflows }) { + const out = []; + if (!c.reversible && c.protected) out.push('Require TTP execution authority bound to these exact parameters'); + if (recordsAffected > 25) out.push(`Limit batch to 25 records (currently ${recordsAffected}) + require approval`); + if (amount >= 5000) out.push(`Require human approval: $${amount} exceeds the $5,000 policy limit`); + if (connectedWorkflows > 2) out.push(`Notify ${connectedWorkflows} connected workflows before executing`); + if (c.severity === 'CRITICAL') out.push('Verify authority at the effect boundary, not in the calling agent'); + return out.length ? out : ['No additional control required for this consequence class']; +} + +// A change in material parameters can change the consequence — and therefore the route. +export function consequenceChanged(before, after) { + return before.severity !== after.severity || before.consequence !== after.consequence || + before.financialExposure !== after.financialExposure || before.recordsAffected !== after.recordsAffected; +} diff --git a/packages/pctr/tests/adapters.test.mjs b/packages/pctr/tests/adapters.test.mjs new file mode 100644 index 0000000..5821093 --- /dev/null +++ b/packages/pctr/tests/adapters.test.mjs @@ -0,0 +1,74 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { normalize, ingest, supportedFrameworks } from '../src/adapters.mjs'; +import { createTimeline, replay } from '../src/timeline.mjs'; + +test('every framework maps its own tool call onto the same security meaning', () => { + const cases = [ + ['openai-agents', { type: 'tool_call', name: 'payments.transfer', arguments: { amount: 18000 }, agent: 'finance' }], + ['claude-agents', { type: 'tool_use', name: 'payments.transfer', input: { amount: 18000 }, agent: 'finance' }], + ['langgraph', { event: 'on_tool_start', name: 'payments.transfer', data: { input: { amount: 18000 } } }], + ['crewai', { type: 'tool_usage_started', tool: 'payments.transfer', tool_args: { amount: 18000 }, agent: 'finance' }], + ['autogen', { type: 'function_call', name: 'payments.transfer', arguments: '{"amount":18000}', sender: 'finance' }], + ['semantic-kernel', { type: 'function_invoking', function: 'payments.transfer', arguments: { amount: 18000 } }], + ['mcp', { method: 'tools/call', params: { name: 'payments.transfer', arguments: { amount: 18000 } } }], + ['generic', { action: 'payments.transfer', params: { amount: 18000 } }] + ]; + for (const [framework, event] of cases) { + const normalized = normalize(framework, event); + assert.equal(normalized.event, 'ACTION_PROPOSED', framework); + assert.equal(normalized.detail.action, 'payments.transfer', framework); + assert.equal(normalized.detail.consequence, 'MONEY_MOVED', framework); + assert.equal(normalized.detail.severity, 'CRITICAL', framework); // $18,000 is over the limit + } +}); + +test('delegation is recognised whatever each framework calls it', () => { + const cases = [ + ['openai-agents', { type: 'handoff', from_agent: 'planner', to_agent: 'finance' }], + ['claude-agents', { type: 'subagent', agent: 'planner', subagent_type: 'finance' }], + ['crewai', { type: 'agent_delegated', from_agent: 'planner', to_agent: 'finance' }], + ['autogen', { type: 'message', sender: 'planner', recipient: 'finance' }], + ['a2a', { type: 'task.delegated', from: 'planner', to: 'finance' }] + ]; + for (const [framework, event] of cases) { + const normalized = normalize(framework, event); + assert.equal(normalized.event, 'AGENT_DELEGATED', framework); + assert.equal(normalized.subject, 'planner', framework); + assert.equal(normalized.detail.to, 'finance', framework); + } +}); + +test('MCP tool listings become capability discovery', () => { + const normalized = normalize('mcp', { method: 'tools/list', server: 'payments', result: { tools: [{ name: 'payments.transfer' }, { name: 'payments.status' }] } }); + assert.equal(normalized.event, 'CAPABILITY_DISCOVERED'); + assert.deepEqual(normalized.detail.actions, ['payments.transfer', 'payments.status']); +}); + +test('framework events without security meaning are dropped, not invented', () => { + assert.equal(normalize('openai-agents', { type: 'token_usage', tokens: 812 }), null); + assert.equal(normalize('langgraph', { event: 'on_llm_new_token', data: { chunk: 'hel' } }), null); + assert.equal(normalize('claude-agents', { type: 'text', text: 'thinking...' }), null); + assert.equal(normalize('openai-agents', null), null); // malformed input must not lose the run +}); + +test('an unknown framework falls back to the generic envelope', () => { + const normalized = normalize('some-new-framework-2027', { action: 'customers.delete', params: { recordsAffected: 900 } }); + assert.equal(normalized.detail.consequence, 'DATA_DELETED'); + assert.ok(supportedFrameworks().includes('generic')); +}); + +test('ingesting a run records proposals with the consequence they imply', () => { + const timeline = createTimeline({ objective: 'Pay invoice' }); + ingest('openai-agents', [ + { type: 'agent_start', agent: 'planner', input: 'Pay invoice INV-4471' }, + { type: 'handoff', from_agent: 'planner', to_agent: 'finance' }, + { type: 'token_usage', tokens: 812 }, + { type: 'tool_call', name: 'payments.transfer', arguments: { amount: 18000 }, agent: 'finance' }, + { type: 'tool_output', name: 'payments.transfer', agent: 'finance' } + ], timeline); + + const events = timeline.events.map((e) => e.event); + assert.deepEqual(events, ['AGENT_STARTED', 'AGENT_DELEGATED', 'ACTION_PROPOSED', 'CONSEQUENCE_DETECTED', 'EXECUTION_COMPLETED']); + assert.ok(replay(timeline).some((e) => e.line.includes('MONEY_MOVED (CRITICAL)'))); +}); diff --git a/packages/pctr/tests/boundary.test.mjs b/packages/pctr/tests/boundary.test.mjs new file mode 100644 index 0000000..ad98360 --- /dev/null +++ b/packages/pctr/tests/boundary.test.mjs @@ -0,0 +1,89 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { buildGraph } from '../src/graph.mjs'; +import { protect } from '../src/protect.mjs'; +import { issueAuthority } from '../src/authority.mjs'; +import { startBoundaryServer, remoteBoundary, createBoundary, persistentReplayStore } from '../src/boundary.mjs'; +import { generateKeyPair, exportPublic } from '../src/keys.mjs'; +import { verifyReceipt } from '../src/receipt.mjs'; + +const graph = () => buildGraph({ + principal: 'user:test', + agents: [{ id: 'finance', trust: 0.99, evidenceAgeSeconds: 5, authority: ['payments.*'], tools: ['payments'] }], + tools: [{ id: 'payments', actions: ['payments.transfer'] }], + actions: [{ id: 'payments.transfer', amount: 100 }], + policy: { requireApprovalAtOrAbove: 'CRITICAL' } +}); + +test('authority is verified out of process, by a boundary the agent does not control', async () => { + const { url, close } = await startBoundaryServer({ port: 0 }); + try { + const run = await protect(graph(), { action: 'payments.transfer', target: 'acct:1', params: { amount: 100 } }, + { boundary: remoteBoundary(url), execute: () => 'sent' }); + assert.equal(run.allowed, true); + assert.equal(run.receipt.verifier.boundary, url); + assert.equal(run.result.output, 'sent'); + } finally { + await close(); + } +}); + +test('an unreachable boundary denies execution; it never fails open', async () => { + const { url, close } = await startBoundaryServer({ port: 0 }); + await close(); // the boundary is now gone + const run = await protect(graph(), { action: 'payments.transfer', target: 'acct:1', params: { amount: 100 } }, + { boundary: remoteBoundary(url, { timeoutMs: 500 }), execute: () => 'sent' }); + assert.equal(run.allowed, false); + assert.ok(run.receipt.verifier.failures.some((f) => f.code === 'BOUNDARY_UNREACHABLE')); + assert.equal(run.result, null); // nothing executed +}); + +test('the boundary rejects an authority signed by a key it does not trust', async () => { + const trusted = generateKeyPair(); + const attacker = generateKeyPair(); + const { url, close } = await startBoundaryServer({ port: 0, boundary: createBoundary({ trustedKeyIds: [trusted.keyId] }) }); + try { + const forged = issueAuthority({ principal: 'user:test', action: 'payments.transfer', target: 'acct:attacker', params: { amount: 999999 }, consequence: 'MONEY_MOVED', keyPair: attacker }); + const boundary = remoteBoundary(url); + const decision = await boundary.verify(forged, { action: 'payments.transfer', target: 'acct:attacker', params: { amount: 999999 }, principal: 'user:test' }); + assert.equal(decision.allowed, false); + assert.ok(decision.failures.some((f) => f.code === 'UNTRUSTED_SIGNER')); + } finally { + await close(); + } +}); + +test('replay protection survives a boundary restart', async () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pctr-boundary-')); + const file = path.join(dir, 'spent-nonces.json'); + const key = generateKeyPair(); + const publicKey = exportPublic(key.publicKey); + const authority = issueAuthority({ principal: 'user:test', action: 'payments.transfer', target: 'acct:1', params: { amount: 100 }, consequence: 'MONEY_MOVED', keyPair: key }); + const execution = { action: 'payments.transfer', target: 'acct:1', params: { amount: 100 }, principal: 'user:test' }; + + const first = createBoundary({ publicKey, replayStore: persistentReplayStore(file) }); + assert.equal(first.verify(authority, execution).allowed, true); + + // A fresh process, reading the same spent-nonce state. + const restarted = createBoundary({ publicKey, replayStore: persistentReplayStore(file) }); + const second = restarted.verify(authority, execution); + assert.equal(second.allowed, false); + assert.ok(second.failures.some((f) => f.code === 'REPLAYED_AUTHORITY')); + fs.rmSync(dir, { recursive: true, force: true }); +}); + +test('the protected loop signs with the key it was given, end to end', async () => { + const key = generateKeyPair(); + const other = generateKeyPair(); + const run = await protect(graph(), { action: 'payments.transfer', target: 'acct:1', params: { amount: 100 } }, + { keyPair: key, publicKey: exportPublic(key.publicKey), execute: () => 'sent' }); + + assert.equal(run.allowed, true); + assert.equal(run.authority.keyId, key.keyId); + assert.equal(verifyReceipt(run.receipt, { publicKey: exportPublic(key.publicKey) }).valid, true); + assert.equal(verifyReceipt(run.receipt, { publicKey: exportPublic(other.publicKey) }).valid, false); +}); diff --git a/packages/pctr/tests/discover.test.mjs b/packages/pctr/tests/discover.test.mjs new file mode 100644 index 0000000..bceeb45 --- /dev/null +++ b/packages/pctr/tests/discover.test.mjs @@ -0,0 +1,102 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { discover } from '../src/discover.mjs'; +import { classifyAction } from '../src/consequences.mjs'; +import { buildGraph, summarize } from '../src/graph.mjs'; + +function project(files) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pctr-discover-')); + for (const [name, content] of Object.entries(files)) { + fs.mkdirSync(path.dirname(path.join(dir, name)), { recursive: true }); + fs.writeFileSync(path.join(dir, name), content); + } + return dir; +} + +test('tool actions are read out of source, not guessed', () => { + const dir = project({ + 'package.json': JSON.stringify({ dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } }), + 'src/server.mjs': ` + const server = new McpServer({ name: 'payments' }); + server.tool('payments.transfer', 'Move money', async () => ({})); + server.registerTool('customers.delete', 'Delete a customer', async () => ({})); + ` + }); + const { manifest } = discover(dir); + const actions = manifest.tools.flatMap((t) => t.actions); + assert.ok(actions.includes('payments.transfer')); + assert.ok(actions.includes('customers.delete')); + assert.ok(manifest.frameworks.includes('mcp')); + fs.rmSync(dir, { recursive: true, force: true }); +}); + +test('python tool and agent declarations are discovered with the right framework', () => { + const dir = project({ + 'requirements.txt': 'crewai\nlangchain\n', + 'agents/finance.py': ` +from crewai import Agent +from langchain.tools import tool + +finance = Agent(role="Finance Agent", goal="pay invoices") + +@tool +def send_invoice_email(to: str): + return True + ` + }); + const { manifest } = discover(dir); + const agent = manifest.agents.find((a) => a.id === 'finance-agent'); + assert.ok(agent, 'expected the declared CrewAI agent'); + assert.equal(agent.framework, 'crewai'); + assert.ok(manifest.tools.flatMap((t) => t.actions).includes('send_invoice_email')); + fs.rmSync(dir, { recursive: true, force: true }); +}); + +test('MCP server configuration is discovered as external tooling', () => { + const dir = project({ '.mcp.json': JSON.stringify({ mcpServers: { payments: { command: 'node', args: ['server.js'] } } }) }); + const { manifest } = discover(dir); + const tool = manifest.tools.find((t) => t.id === 'payments'); + assert.equal(tool.protocol, 'mcp'); + fs.rmSync(dir, { recursive: true, force: true }); +}); + +test('declared facts in an existing manifest override what discovery inferred', () => { + const dir = project({ + 'package.json': JSON.stringify({ dependencies: { openai: '^4.0.0' } }), + 'src/agent.mjs': 'export const agent = {};' + }); + const { manifest } = discover(dir, { declared: { principal: 'user:ops', agents: [{ id: 'agent', trust: 0.99, authority: ['payments.*'] }] } }); + const agent = manifest.agents.find((a) => a.id === 'agent'); + assert.equal(agent.trust, 0.99); + assert.deepEqual(agent.authority, ['payments.*']); + assert.equal(manifest.principal, 'user:ops'); + fs.rmSync(dir, { recursive: true, force: true }); +}); + +test('the verb decides the consequence, not the namespace it sits in', () => { + assert.equal(classifyAction('payments.status').consequence, 'DATA_READ'); + assert.equal(classifyAction('payments.transfer').consequence, 'MONEY_MOVED'); + assert.equal(classifyAction('customers.list').consequence, 'DATA_READ'); + assert.equal(classifyAction('customers.delete').consequence, 'DATA_DELETED'); + assert.equal(classifyAction('send_invoice_email').consequence, 'MESSAGE_SENT'); +}); + +test('a discovered project produces a usable graph without any hand editing', () => { + const dir = project({ + 'package.json': JSON.stringify({ dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } }), + 'src/ops-agent.mjs': ` + const server = new McpServer({ name: 'infra' }); + server.tool('cluster.deploy', 'Deploy', async () => ({})); + ` + }); + const { manifest } = discover(dir); + const graph = buildGraph(manifest); + const summary = summarize(graph); + assert.ok(summary.agents >= 1); + assert.ok(summary.protected >= 1, 'deploying to a cluster is a protected consequence'); + fs.rmSync(dir, { recursive: true, force: true }); +}); diff --git a/packages/pctr/tests/pctr.test.mjs b/packages/pctr/tests/pctr.test.mjs new file mode 100644 index 0000000..ef13261 --- /dev/null +++ b/packages/pctr/tests/pctr.test.mjs @@ -0,0 +1,268 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; + +import { classifyAction } from '../src/consequences.mjs'; +import { buildGraph, pathsToAction, reachableActions, protectedActions, summarize } from '../src/graph.mjs'; +import { previewConsequence, consequenceChanged } from '../src/twin.mjs'; +import { resolveRoute, reroute } from '../src/router.mjs'; +import { issueAuthority, verifyAuthority, createReplayStore } from '../src/authority.mjs'; +import { issueReceipt, verifyReceipt, verifyReceiptChain } from '../src/receipt.mjs'; +import { createTimeline, why, compare, fork, replay } from '../src/timeline.mjs'; +import { protect, simulate } from '../src/protect.mjs'; +import { generateKeyPair, exportPublic } from '../src/keys.mjs'; + +const manifest = () => ({ + principal: 'user:test', + agents: [ + { id: 'planner', trust: 0.98, evidenceAgeSeconds: 10, authority: ['*'], jurisdiction: 'eu', latencyMs: 50, tools: [], delegatesTo: ['finance-a', 'finance-d'] }, + { id: 'finance-a', trust: 0.97, evidenceAgeSeconds: 4200, authority: ['payments.*'], jurisdiction: 'eu', latencyMs: 10, tools: ['payments'] }, + { id: 'finance-d', trust: 0.97, evidenceAgeSeconds: 20, authority: ['payments.*'], jurisdiction: 'eu', latencyMs: 90, tools: ['payments'] } + ], + tools: [{ id: 'payments', protocol: 'mcp', actions: ['payments.transfer', 'reports.read'] }], + actions: [{ id: 'payments.transfer', amount: 1800 }], + policy: { requireApprovalAtOrAbove: 'CRITICAL', approvalThresholds: { amount: 5000 }, maxHops: 6, decayPerHop: 0.05 } +}); +const graph = () => buildGraph(manifest()); + +test('consequences are classified from what the action can cause', () => { + assert.equal(classifyAction('customers.delete').consequence, 'DATA_DELETED'); + assert.equal(classifyAction('payments.transfer').consequence, 'MONEY_MOVED'); + assert.equal(classifyAction('reports.read').protected, false); + // Scale raises severity even when the verb looks benign. + assert.equal(classifyAction('records.update', { recordsAffected: 5000 }).severity, 'CRITICAL'); +}); + +test('the graph maps consequences backward to every principal that can reach them', () => { + const g = graph(); + const paths = pathsToAction(g, 'payments.transfer'); + assert.equal(paths.length, 2); + for (const p of paths) assert.equal(p[0], 'user:test'); + assert.equal(reachableActions(g, 'planner').length, 4); + assert.equal(protectedActions(g)[0].id, 'payments.transfer'); + assert.equal(summarize(g).agents, 3); +}); + +test('consequence twin reports blast radius and recommends controls before execution', () => { + const p = previewConsequence(graph(), 'payments.transfer', { amount: 18000 }); + assert.equal(p.severity, 'CRITICAL'); + assert.equal(p.reversible, false); + assert.equal(p.financialExposure, 18000); + assert.equal(p.routesThatCanReachIt, 2); + assert.ok(p.recommendations.some((r) => r.includes('5,000'))); + assert.ok(consequenceChanged(previewConsequence(graph(), 'payments.transfer', { amount: 1800 }), p)); +}); + +test('routing removes stale evidence before it optimizes for latency', () => { + const r = resolveRoute(graph(), 'payments.transfer'); + assert.equal(r.selected.agents.at(-1), 'finance-d'); + const rejected = r.candidates.find((c) => c.agents.includes('finance-a')); + assert.ok(rejected.rejections.some((x) => x.code === 'STALE_EVIDENCE')); + // finance-a is the faster route and is still not selected: security is not traded for latency. + assert.ok(rejected.latencyMs < r.selected.latencyMs); +}); + +test('routing removes routes whose agents lack authority for the action', () => { + const m = manifest(); + m.agents[2].authority = ['reports.read']; + const r = resolveRoute(buildGraph(m), 'payments.transfer'); + assert.equal(r.selected, null); + assert.ok(r.candidates.flatMap((c) => c.rejections).some((x) => x.code === 'INSUFFICIENT_AUTHORITY')); +}); + +test('routing removes consequence-incompatible jurisdictions', () => { + const m = manifest(); + m.policy.jurisdictions = { MONEY_MOVED: ['us'] }; + const r = resolveRoute(buildGraph(m), 'payments.transfer'); + assert.equal(r.selected, null); + assert.ok(r.candidates.flatMap((c) => c.rejections).some((x) => x.code === 'JURISDICTION_INCOMPATIBLE')); +}); + +test('authority never silently expands during rerouting', () => { + const g = graph(); + const previous = resolveRoute(g, 'payments.transfer'); + const next = reroute(g, 'payments.transfer', previous, { severity: 'MEDIUM' }); + assert.equal(next.selected, null); + assert.equal(next.expansionBlocked, true); +}); + +test('authority binds the exact execution, not the credential', () => { + const g = graph(); + const route = resolveRoute(g, 'payments.transfer').selected; + const authority = issueAuthority({ + principal: 'user:test', action: 'payments.transfer', target: 'acct:9931', + params: { amount: 1800 }, consequence: 'MONEY_MOVED', route + }); + const ok = verifyAuthority(authority, { action: 'payments.transfer', target: 'acct:9931', params: { amount: 1800 }, principal: 'user:test' }); + assert.equal(ok.allowed, true); + + // Same valid authority, changed amount: possession is not authority. + const tampered = verifyAuthority(authority, { action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 }, principal: 'user:test' }); + assert.equal(tampered.allowed, false); + assert.ok(tampered.failures.some((f) => f.code === 'PARAMETER_MISMATCH')); + + // Same authority, different target. + const redirected = verifyAuthority(authority, { action: 'payments.transfer', target: 'acct:0001', params: { amount: 1800 }, principal: 'user:test' }); + assert.ok(redirected.failures.some((f) => f.code === 'TARGET_MISMATCH')); +}); + +test('authority expires and cannot be replayed', () => { + const authority = issueAuthority({ + principal: 'user:test', action: 'payments.transfer', target: 'acct:1', params: { amount: 1 }, + consequence: 'MONEY_MOVED', validForSeconds: 60, issuedAt: '2026-01-01T00:00:00.000Z' + }); + const execution = { action: 'payments.transfer', target: 'acct:1', params: { amount: 1 }, principal: 'user:test' }; + const expired = verifyAuthority(authority, execution, { now: '2026-01-01T00:05:00.000Z' }); + assert.ok(expired.failures.some((f) => f.code === 'AUTHORITY_EXPIRED')); + + const replayStore = createReplayStore(); + const at = '2026-01-01T00:00:30.000Z'; + assert.equal(verifyAuthority(authority, execution, { now: at, replayStore }).allowed, true); + const second = verifyAuthority(authority, execution, { now: at, replayStore }); + assert.ok(second.failures.some((f) => f.code === 'REPLAYED_AUTHORITY')); +}); + +test('tampered authority fails its binding check', () => { + const authority = issueAuthority({ principal: 'user:test', action: 'a', target: 't', params: {}, consequence: 'NONE' }); + const forged = { ...authority, action: 'payments.transfer' }; + const result = verifyAuthority(forged, { action: 'payments.transfer', target: 't', params: {}, principal: 'user:test' }); + assert.equal(result.allowed, false); + assert.ok(result.failures.some((f) => f.code === 'BINDING_HASH_MISMATCH')); +}); + +test('receipts are verifiable against the signing key and detect alteration', () => { + const receipt = issueReceipt({ + request: { action: 'payments.transfer', target: 'acct:1', params: { amount: 1800 } }, + preview: previewConsequence(graph(), 'payments.transfer', { amount: 1800 }), + route: resolveRoute(graph(), 'payments.transfer').selected, + authority: issueAuthority({ principal: 'user:test', action: 'payments.transfer', target: 'acct:1', params: { amount: 1800 }, consequence: 'MONEY_MOVED' }), + verification: { decision: 'EXECUTION_ALLOWED', failures: [] }, + result: { status: 'SUCCEEDED' } + }); + assert.equal(verifyReceipt(receipt).valid, true); + const altered = { ...receipt, requested: { ...receipt.requested, params: { amount: 18000 } } }; + assert.equal(verifyReceipt(altered).valid, false); +}); + +test('the full protected loop denies, then allows once approval is recorded', async () => { + const g = graph(); + const request = { action: 'payments.transfer', target: 'acct:9931', params: { amount: 18000 } }; + + const denied = await protect(g, request); + assert.equal(denied.allowed, false); + assert.ok(denied.receipt.verifier.failures.some((f) => f.code === 'APPROVAL_REQUIRED')); + assert.equal(denied.receipt.executed, null); + + const allowed = await protect(g, request, { approval: { by: 'maurice' }, execute: () => 'transferred' }); + assert.equal(allowed.allowed, true); + assert.equal(allowed.result.output, 'transferred'); + assert.equal(verifyReceipt(allowed.receipt).valid, true); + assert.equal(allowed.receipt.authorityBound.materialParams.amount, 18000); +}); + +test('simulation runs the whole loop without causing an effect', async () => { + let sideEffects = 0; + const run = await simulate(graph(), { action: 'payments.transfer', target: 'acct:1', params: { amount: 100 } }, + { approval: { by: 'maurice' }, execute: () => { sideEffects++; } }); + assert.equal(sideEffects, 0); + assert.equal(run.result.status, 'SIMULATED'); +}); + +test('a receipt can never record an execution that was not allowed', () => { + const receipt = issueReceipt({ + request: { action: 'payments.transfer', target: 'acct:1', params: {} }, + verification: { decision: 'EXECUTION_DENIED', failures: [{ code: 'APPROVAL_REQUIRED', message: 'no approval' }] }, + result: { status: 'SUCCEEDED' } + }); + const result = verifyReceipt(receipt); + assert.equal(result.valid, false); + assert.ok(result.failures.some((f) => f.code === 'EXECUTED_WITHOUT_AUTHORITY')); +}); + +test('receipt chains detect a removed or reordered receipt', () => { + const make = (prior) => issueReceipt({ + request: { action: 'reports.read', target: 'r', params: {} }, + verification: { decision: 'EXECUTION_ALLOWED', failures: [] }, priorReceiptHash: prior + }); + const first = make(null); + const second = make(first.receiptHash); + assert.equal(verifyReceiptChain([first, second]).valid, true); + assert.equal(verifyReceiptChain([second, first]).valid, false); +}); + +test('the time machine explains why deterministically from recorded causes', async () => { + const run = await protect(graph(), { action: 'payments.transfer', target: 'acct:1', params: { amount: 18000 } }); + const answer = why(run.timeline, 'EXECUTION_DENIED'); + assert.equal(answer.found, true); + assert.match(answer.answer, /human approval/i); + assert.ok(answer.because.some((b) => /MONEY_MOVED/.test(b))); + assert.ok(replay(run.timeline).length > 3); +}); + +test('runs can be forked and compared to see where behaviour diverged', async () => { + const request = { action: 'payments.transfer', target: 'acct:1', params: { amount: 18000 } }; + const denied = await protect(graph(), request, { timeline: createTimeline({ runId: 'a' }) }); + const allowed = await protect(graph(), request, { timeline: createTimeline({ runId: 'b' }), approval: { by: 'maurice' } }); + const diff = compare(denied.timeline, allowed.timeline); + assert.equal(diff.sameOutcome, false); + assert.ok(diff.divergedAt > 0); + assert.equal(fork(denied.timeline, { upTo: 'e2' }).events.length, 3); +}); + +test('only canonical security events can enter a timeline', () => { + const t = createTimeline(); + assert.throws(() => t.record('SOMETHING_FRAMEWORK_SPECIFIC', {}), /canonical/); +}); + +test('a receipt can be verified by someone who cannot mint one', () => { + const issuer = generateKeyPair(); + const attacker = generateKeyPair(); + const issuerPublicKey = exportPublic(issuer.publicKey); + + const genuine = issueReceipt({ + request: { action: 'payments.transfer', target: 'acct:1', params: { amount: 1800 } }, + verification: { decision: 'EXECUTION_ALLOWED', failures: [] }, result: { status: 'SUCCEEDED' }, keyPair: issuer + }); + const forged = issueReceipt({ + request: { action: 'payments.transfer', target: 'acct:attacker', params: { amount: 999999 } }, + verification: { decision: 'EXECUTION_ALLOWED', failures: [] }, result: { status: 'SUCCEEDED' }, keyPair: attacker + }); + + const checked = verifyReceipt(genuine, { publicKey: issuerPublicKey }); + assert.equal(checked.valid, true); + assert.equal(checked.signerVerified, true); + + // The forgery is internally consistent, so it must be rejected on the signer. + assert.equal(verifyReceipt(forged, { publicKey: issuerPublicKey }).valid, false); + assert.ok(verifyReceipt(forged, { trustedKeyIds: [issuer.keyId] }).failures.some((f) => f.code === 'UNTRUSTED_SIGNER')); +}); + +test('verifying without pinning a signer is reported as unpinned, not as proof', () => { + const receipt = issueReceipt({ + request: { action: 'reports.read', target: 'r', params: {} }, + verification: { decision: 'EXECUTION_ALLOWED', failures: [] }, keyPair: generateKeyPair() + }); + const result = verifyReceipt(receipt); + assert.equal(result.valid, true); + assert.equal(result.signerVerified, false); + assert.ok(result.warnings.some((w) => w.code === 'UNPINNED_KEY')); +}); + +test('a signature cannot be moved onto an authority signed by another key', () => { + const issuer = generateKeyPair(); + const attacker = generateKeyPair(); + const authority = issueAuthority({ principal: 'user:test', action: 'payments.transfer', target: 'acct:1', params: { amount: 1 }, consequence: 'MONEY_MOVED', keyPair: issuer }); + const swapped = { ...authority, signerPublicKey: exportPublic(attacker.publicKey) }; + const execution = { action: 'payments.transfer', target: 'acct:1', params: { amount: 1 }, principal: 'user:test' }; + assert.equal(verifyAuthority(swapped, execution).allowed, false); + assert.equal(verifyAuthority(authority, execution, { publicKey: exportPublic(issuer.publicKey) }).allowed, true); +}); + +test('material parameters change the consequence, and the consequence sets the trust bar', () => { + const g = graph(); + const small = previewConsequence(g, 'payments.transfer', { amount: 1800 }); + const large = previewConsequence(g, 'payments.transfer', { amount: 18000 }); + assert.equal(small.severity, 'HIGH'); + assert.equal(large.severity, 'CRITICAL'); + assert.equal(resolveRoute(g, 'payments.transfer', { severity: small.severity }).trustRequired, 0.75); + assert.equal(resolveRoute(g, 'payments.transfer', { severity: large.severity }).trustRequired, 0.9); +}); From f10428a74b3e629a0eb16b0d77a0785038a7a624 Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Tue, 15 Sep 2026 08:08:51 -0400 Subject: [PATCH 5/7] Make PCTR installable, shareable and legible at a glance Adoption work: the tool now installs as a standalone package, produces something worth sharing, and shows what it does in one image. - Vendor the three TTP primitives PCTR uses (canonical hashing, trust decay, route verification) so installing PCTR pulls in nothing else. tests/conformance.test.mjs compares them against the reference implementation on every run, so the copies cannot drift silently. Verified by packing the tarball and running the CLI in a clean project. - pctr scan --share writes a Markdown report card: severity table, the highest-priority consequence with the route that reaches it, what to do about it, and a shields.io badge. It leads with the consequence, not with agent counts. - A composite GitHub Action plus an example workflow: scan on every pull request, post the findings as one comment that updates in place, and optionally fail the build when an agent can reach an irreversible consequence. - init --no-example keeps an empty scan empty, so CI never reports fabricated findings about someone's repository. - assets/pctr-scan.svg is generated from real CLI output by scripts/render-terminal-svg.mjs (npm run assets:pctr), so the picture in the README cannot drift from what the tool prints. - npm metadata for publication: description, keywords, repository, homepage, bugs, license file. Command strings in the docs stay true today: the package is not published yet, so the quickstart is npm link rather than npx. Co-Authored-By: Claude Opus 5 --- README.md | 34 +--- assets/pctr-scan.svg | 41 ++++ package.json | 3 +- packages/pctr/LICENSE | 181 ++++++++++++++++++ packages/pctr/README.md | 67 +++---- packages/pctr/action.yml | 94 +++++++++ packages/pctr/bin/pctr.mjs | 21 +- packages/pctr/examples/pctr-scan.yml | 27 +++ packages/pctr/package.json | 59 +++++- packages/pctr/scripts/render-terminal-svg.mjs | 109 +++++++++++ packages/pctr/src/authority.mjs | 2 +- packages/pctr/src/index.mjs | 1 + packages/pctr/src/receipt.mjs | 2 +- packages/pctr/src/report.mjs | 88 +++++++++ packages/pctr/src/ttp.mjs | 87 ++++++++- packages/pctr/tests/conformance.test.mjs | 64 +++++++ packages/pctr/tests/report.test.mjs | 53 +++++ 17 files changed, 851 insertions(+), 82 deletions(-) create mode 100644 assets/pctr-scan.svg create mode 100644 packages/pctr/LICENSE create mode 100644 packages/pctr/action.yml create mode 100644 packages/pctr/examples/pctr-scan.yml create mode 100644 packages/pctr/scripts/render-terminal-svg.mjs create mode 100644 packages/pctr/src/report.mjs create mode 100644 packages/pctr/tests/conformance.test.mjs create mode 100644 packages/pctr/tests/report.test.mjs diff --git a/README.md b/README.md index 48eca07..35561c0 100644 --- a/README.md +++ b/README.md @@ -54,35 +54,19 @@ Objective -> Trust Route -> Consequence Preview -> Execution Authority -> | **3. Authority** | Is this exact execution allowed right now? | `pctr protect ` | ```bash -npm run pctr -- init # discover agents and tools, write pctr.json -npm run pctr -- scan # what consequences can they reach? +npm link ./packages/pctr # not on npm yet; link it from a clone +pctr init # discover agents and tools, write pctr.json +pctr scan # what consequences can they reach? ``` -``` -Agents found 5 -Tools found 3 -Potential actions 4 - -Protected consequences - -CRITICAL 1 -HIGH 1 -MEDIUM 1 - -Highest priority: - -customers.delete - -Problem: - -The final action can cause "data deleted" irreversibly without independent execution authority. - -Recommended: +

    + pctr scan finds five agents, three tools and four potential actions, and reports one critical protected consequence +

    -Add TTP authority verification before customers.delete. -``` +`pctr scan --share` turns that into Markdown you can paste into a pull request, and +`packages/pctr/examples/pctr-scan.yml` runs it on every PR as a comment. -No account, no network: everything stays in `./pctr.json` and `./.pctr`. PCTR is not published to npm yet — run it from a clone, or `npm link ./packages/pctr` for the bare `pctr` command. Three flagship capabilities sit on top of that graph — the **Consequence Twin** (`pctr preview`), **TrustRoute Autopilot** (`pctr route`), and the **Agent Time Machine** (`pctr replay`, `pctr explain`) — with Ed25519-signed receipts, read-only probes that measure a consequence instead of declaring it, adapters for the common agent frameworks, and an effect boundary (`pctr serve`) that verifies authority in its own process. See the [PCTR README](packages/pctr/README.md), `npm run demo:pctr` and `npm run demo:pctr-fabric`. +No account, no network: everything stays in `./pctr.json` and `./.pctr`. Three flagship capabilities sit on top of that graph — the **Consequence Twin** (`pctr preview`), **TrustRoute Autopilot** (`pctr route`), and the **Agent Time Machine** (`pctr replay`, `pctr explain`) — with Ed25519-signed receipts, read-only probes that measure a consequence instead of declaring it, adapters for the common agent frameworks, and an effect boundary (`pctr serve`) that verifies authority in its own process. See the [PCTR README](packages/pctr/README.md), `npm run demo:pctr` and `npm run demo:pctr-fabric`. PCTR routes to the consequence. TTP binds the authority for the exact execution that reaches it. diff --git a/assets/pctr-scan.svg b/assets/pctr-scan.svg new file mode 100644 index 0000000..e828d70 --- /dev/null +++ b/assets/pctr-scan.svg @@ -0,0 +1,41 @@ + + + + + + pctr scan + + PCTR + + Scanning your agents... + + Agents found 5 + Tools found 3 + External systems 3 + Potential actions 4 + + Protected consequences + + CRITICAL 1 + HIGH 1 + MEDIUM 1 + + Highest priority: + + customers.delete + + Route: + + user:local → planner → support-agent → admin-agent → database → customers.delete + + Problem: + + The final action can cause "data deleted" irreversibly without independent + execution authority. + + Recommended: + + Add TTP authority verification before customers.delete. + + + diff --git a/package.json b/package.json index 3a31dcf..4733657 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "test:pctr": "node --test packages/pctr/tests/*.test.mjs", "pctr": "node packages/pctr/bin/pctr.mjs", "demo:pctr": "node examples/pctr-consequence-change-demo.mjs", - "demo:pctr-fabric": "node examples/pctr-universal-fabric-demo.mjs" + "demo:pctr-fabric": "node examples/pctr-universal-fabric-demo.mjs", + "assets:pctr": "node packages/pctr/scripts/render-terminal-svg.mjs" }, "devDependencies": { "@fontsource/inter": "^5.2.8", diff --git a/packages/pctr/LICENSE b/packages/pctr/LICENSE new file mode 100644 index 0000000..aba8dbd --- /dev/null +++ b/packages/pctr/LICENSE @@ -0,0 +1,181 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship made available under + the License, as indicated by a copyright notice that is included in + or attached to the work (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other transformations + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean, as submitted to the Licensor for inclusion + in the Work by the copyright owner or by an individual or Legal Entity + authorized to submit on behalf of the copyright owner. For the purposes + of this definition, "submitted" means any form of electronic, verbal, + or written communication sent to the Licensor or its representatives, + including but not limited to communication on electronic mailing lists, + source code control systems, and issue tracking systems that are managed + by, or on behalf of, the Licensor for the purpose of discussing and + improving the Work, but excluding communication that is conspicuously + marked or designated in writing by the copyright owner as "Not a + Contribution." + + "Contributor" shall mean Licensor and any Legal Entity on behalf of + whom a Contribution has been received by the Licensor and included + within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by the combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a cross-claim + or counterclaim in a lawsuit) alleging that the Work or any + Contribution embodied within the Work constitutes direct or contributory + patent infringement, then any patent licenses granted to You under + this License for that Work shall terminate as of the date such + litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative + Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, You must include a readable copy of the + attribution notices contained within such NOTICE file, in + at least one of the following places: within a NOTICE text + file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the + Derivative Works, if and wherever such third-party notices + normally appear. The contents of the NOTICE file are for + informational purposes only and do not modify the License. + You may add Your own attribution notices within Derivative + Works that You distribute, alongside or in addition to the + NOTICE text from the Work, provided that such additional + attribution notices cannot be construed as modifying the License. + + You may add Your own license statement for Your modifications and + may provide additional grant of rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Work. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any conditions of + TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or reproducing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or exemplary damages of any character arising as a + result of this License or out of the use or inability to use the + Work (even if such Contributor has been advised of the possibility + of such damages). + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may offer only + obligations consistent on Your own behalf and on Your sole + responsibility, not on behalf of any other Contributor, and only + if You agree to indemnify, defend, and hold each Contributor + harmless for any liability incurred by, or claims asserted against, + such Contributor by reason of your accepting any such warranty or + additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2026 BlockSiFr + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/pctr/README.md b/packages/pctr/README.md index 30847c5..e6d7bc7 100644 --- a/packages/pctr/README.md +++ b/packages/pctr/README.md @@ -10,62 +10,45 @@ Objective -> Trust Route -> Consequence Preview -> Execution Authority -> ## 60 seconds -Not published to npm yet. From a clone of this repo: +pctr scan finds five agents, three tools and four potential actions, and reports one critical protected consequence: customers.delete can be reached through support-agent and admin-agent without independent execution authority + +Not on npm yet — from a clone of this repo: ```bash -npm run pctr -- init # discover agents and tools, write pctr.json -npm run pctr -- scan # what consequences can they reach? +npm link ./packages/pctr # then the bare `pctr` command works anywhere +pctr init # discover agents and tools, write pctr.json +pctr scan # what consequences can they reach? ``` -Or link it to get the bare `pctr` command: `npm link ./packages/pctr`. - -``` -PCTR +No account. No network. Everything stays in `./pctr.json` and `./.pctr`. -Scanning your agents... +## Share what you find -Agents found 5 -Tools found 3 -External systems 3 -Potential actions 4 +```bash +pctr scan --share # writes pctr-report.md +``` -Protected consequences +Drops straight into a pull request or an issue: a severity table, the highest-priority +consequence with the route that reaches it, and what to do about it. Add +`packages/pctr/examples/pctr-scan.yml` to `.github/workflows/` and every PR gets the same +report as a comment, with `fail-on: critical` to block a merge when an agent can reach an +irreversible consequence. -CRITICAL 1 -HIGH 1 -MEDIUM 1 +```markdown +## 🛑 PCTR consequence scan -Highest priority: +**5 agents · 3 tools · 4 actions.** 3 of them can cause a protected consequence, and 2 cannot be undone. -customers.delete +| Severity | Consequences | +| --- | --- | +| 🔴 CRITICAL | 1 | +| 🟠 HIGH | 1 | -Route: +### Highest priority: `customers.delete` -user:local - | - v -support-agent - | - v -admin-agent - | - v -database - | - v -customers.delete - -Problem: - -The final action can cause "data deleted" irreversibly without independent execution authority. - -Recommended: - -Add TTP authority verification before customers.delete. +Causes **data deleted** · **irreversible** · 1,842 records · blast radius WIDE ``` -No account. No network. Everything stays in `./pctr.json` and `./.pctr`. - ## The three questions | Question | Command | Answers | diff --git a/packages/pctr/action.yml b/packages/pctr/action.yml new file mode 100644 index 0000000..dcffc03 --- /dev/null +++ b/packages/pctr/action.yml @@ -0,0 +1,94 @@ +name: 'PCTR consequence scan' +description: 'See what your AI agents can cause, before they cause it. Maps agents, tools and actions to the consequences they can reach.' +author: 'BlockSiFr' +branding: + icon: 'shield' + color: 'red' + +inputs: + working-directory: + description: 'Directory to scan.' + required: false + default: '.' + comment: + description: 'Post the findings as a pull request comment (updates the same comment on each run).' + required: false + default: 'true' + fail-on: + description: 'Fail the job when a consequence at this severity or above is reachable: none, critical, high, or medium.' + required: false + default: 'none' + version: + description: 'Version of @blocksifr/pctr to run.' + required: false + default: 'latest' + +outputs: + critical: + description: 'Number of CRITICAL consequences reachable.' + value: ${{ steps.scan.outputs.critical }} + high: + description: 'Number of HIGH consequences reachable.' + value: ${{ steps.scan.outputs.high }} + report: + description: 'Path to the Markdown report.' + value: ${{ steps.scan.outputs.report }} + +runs: + using: composite + steps: + - id: scan + shell: bash + working-directory: ${{ inputs.working-directory }} + run: | + set -euo pipefail + PCTR="npx --yes @blocksifr/pctr@${{ inputs.version }}" + + # init is additive: an existing pctr.json is kept and only extended. + $PCTR init > /dev/null + $PCTR scan --share pctr-report.md > /dev/null + $PCTR scan --json > pctr-scan.json + + CRITICAL=$(node -p "require('./pctr-scan.json').summary.bySeverity.CRITICAL") + HIGH=$(node -p "require('./pctr-scan.json').summary.bySeverity.HIGH") + MEDIUM=$(node -p "require('./pctr-scan.json').summary.bySeverity.MEDIUM") + + { + echo "critical=$CRITICAL" + echo "high=$HIGH" + echo "medium=$MEDIUM" + echo "report=${{ inputs.working-directory }}/pctr-report.md" + } >> "$GITHUB_OUTPUT" + + cat pctr-report.md >> "$GITHUB_STEP_SUMMARY" + + case "${{ inputs.fail-on }}" in + critical) THRESHOLD=$CRITICAL ;; + high) THRESHOLD=$((CRITICAL + HIGH)) ;; + medium) THRESHOLD=$((CRITICAL + HIGH + MEDIUM)) ;; + *) THRESHOLD=0 ;; + esac + if [ "$THRESHOLD" -gt 0 ]; then + echo "::error::$THRESHOLD consequence(s) at or above '${{ inputs.fail-on }}' can be reached by these agents. See the job summary." + exit 1 + fi + + - if: ${{ always() && inputs.comment == 'true' && github.event_name == 'pull_request' }} + shell: bash + working-directory: ${{ inputs.working-directory }} + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + MARKER='' + printf '%s\n%s' "$MARKER" "$(cat pctr-report.md)" > pctr-comment.md + + # Update the existing comment rather than adding one per push. + EXISTING=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ + --jq "map(select(.body | contains(\"$MARKER\"))) | .[0].id // empty") + + if [ -n "$EXISTING" ]; then + gh api --method PATCH "repos/${{ github.repository }}/issues/comments/$EXISTING" -F body=@pctr-comment.md > /dev/null + else + gh api --method POST "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" -F body=@pctr-comment.md > /dev/null + fi diff --git a/packages/pctr/bin/pctr.mjs b/packages/pctr/bin/pctr.mjs index 69f3ddb..416510e 100755 --- a/packages/pctr/bin/pctr.mjs +++ b/packages/pctr/bin/pctr.mjs @@ -12,6 +12,7 @@ import { defaultKeyPair, exportPublic } from '../src/keys.mjs'; import fs from 'node:fs'; import path from 'node:path'; import * as store from '../src/store.mjs'; +import { renderReport, badgeUrl } from '../src/report.mjs'; import * as r from '../src/render.mjs'; const VERSION = '0.1.0'; @@ -20,7 +21,7 @@ const argv = process.argv.slice(2); const command = argv[0]; // Flags that take a value, so their value is never mistaken for a positional argument. const VALUE_FLAGS = new Set(['amount', 'records', 'recordsAffected', 'batch', 'params', 'approve', - 'target', 'agent', 'objective', 'compare', 'fork', 'key', 'export', 'run', 'probe', 'boundary', 'port']); + 'target', 'agent', 'objective', 'compare', 'fork', 'key', 'export', 'run', 'probe', 'boundary', 'port', 'share']); const positional = (() => { const out = []; for (let i = 1; i < argv.length; i++) { @@ -84,7 +85,9 @@ async function main() { case 'init': { const existing = store.readManifest(); const { manifest, notes, discovered } = discover(process.cwd(), { declared: existing }); - if (!manifest.agents.length) { + // In CI a fabricated example would produce a false report about someone's repo, + // so --no-example keeps an empty scan empty. + if (!manifest.agents.length && !argv.includes('--no-example')) { manifest.agents = exampleManifest().agents; manifest.tools = exampleManifest().tools; manifest.actions = exampleManifest().actions; @@ -103,7 +106,16 @@ async function main() { case 'scan': { const graph = loadGraph(); - return out(r.renderScan(graph), { summary: summarize(graph), protected: protectedActions(graph) }); + if (flag('share')) { + const report = renderReport(graph); + const file = flag('share') !== true ? String(flag('share')) : 'pctr-report.md'; + fs.writeFileSync(file, report); + if (asJson) return out(null, { file, report, badge: badgeUrl(graph) }); + console.log(report); + console.log(r.dim(`Written to ${file} — paste it into a PR, an issue, or a message.`)); + return 0; + } + return out(r.renderScan(graph), { summary: summarize(graph), protected: protectedActions(graph), badge: badgeUrl(graph) }); } case 'graph': { @@ -339,6 +351,7 @@ function help() { Usage pctr init Discover agents and tools, write pctr.json pctr scan What consequences can your agents reach? + pctr scan --share Write the findings as shareable Markdown pctr graph Show the trust graph pctr preview Consequence Twin: what will this change? pctr route TrustRoute Autopilot: which path may get there? @@ -354,6 +367,8 @@ Usage Options --json Machine-readable output + --share [file] scan: write the findings as shareable Markdown + --no-example init: don't write a worked example when nothing is found --amount Material parameter: amount --records Material parameter: records affected --params '' Any other material parameters diff --git a/packages/pctr/examples/pctr-scan.yml b/packages/pctr/examples/pctr-scan.yml new file mode 100644 index 0000000..dfcd83f --- /dev/null +++ b/packages/pctr/examples/pctr-scan.yml @@ -0,0 +1,27 @@ +# See what your agents can cause, on every pull request. +# Copy this to .github/workflows/pctr-scan.yml +name: PCTR consequence scan + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + pull-requests: write # so the scan can post its findings on the PR + +jobs: + scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + + - uses: BlockSiFr/ttp-protocol/packages/pctr@main + with: + comment: 'true' + # Fail the build when an agent can reach an irreversible consequence. + # Start with 'none' to see the report, then tighten to 'critical'. + fail-on: 'none' diff --git a/packages/pctr/package.json b/packages/pctr/package.json index 24276b5..89442d9 100644 --- a/packages/pctr/package.json +++ b/packages/pctr/package.json @@ -1,12 +1,59 @@ { "name": "@blocksifr/pctr", "version": "0.1.0", - "description": "PCTR — Protected Consequence Trust Routing. See what your agents can cause. Route them safely. Prove what happened.", + "description": "See what your AI agents can cause, route them safely, and prove what happened. Consequence preview, trust routing and signed execution receipts for AI agents.", "type": "module", "license": "Apache-2.0", - "bin": { "pctr": "./bin/pctr.mjs" }, - "exports": { ".": "./src/index.mjs" }, - "engines": { "node": ">=18" }, - "files": ["src/", "bin/", "README.md"], - "scripts": { "test": "node --test tests/*.test.mjs" } + "bin": { + "pctr": "./bin/pctr.mjs" + }, + "exports": { + ".": "./src/index.mjs" + }, + "engines": { + "node": ">=18" + }, + "files": [ + "src/", + "bin/", + "README.md", + "LICENSE" + ], + "scripts": { + "test": "node --test tests/*.test.mjs" + }, + "keywords": [ + "ai-agents", + "agent-security", + "ai-security", + "llm", + "mcp", + "model-context-protocol", + "langgraph", + "crewai", + "autogen", + "openai-agents", + "claude", + "agent-authorization", + "execution-authority", + "audit", + "receipts", + "zero-trust", + "ai-governance", + "agentic" + ], + "homepage": "https://github.com/BlockSiFr/ttp-protocol/tree/main/packages/pctr#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/BlockSiFr/ttp-protocol.git", + "directory": "packages/pctr" + }, + "bugs": { + "url": "https://github.com/BlockSiFr/ttp-protocol/issues" + }, + "author": "BlockSiFr", + "publishConfig": { + "access": "public" + }, + "dependencies": {} } diff --git a/packages/pctr/scripts/render-terminal-svg.mjs b/packages/pctr/scripts/render-terminal-svg.mjs new file mode 100644 index 0000000..596b434 --- /dev/null +++ b/packages/pctr/scripts/render-terminal-svg.mjs @@ -0,0 +1,109 @@ +#!/usr/bin/env node +// Renders a terminal SVG of a real `pctr scan`, so the picture in the README is +// generated from the actual output and cannot drift from what the tool prints. +// Usage: node packages/pctr/scripts/render-terminal-svg.mjs [outfile] +import { execFileSync } from 'node:child_process'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const cli = path.join(here, '..', 'bin', 'pctr.mjs'); +const outFile = process.argv[2] ?? path.join(here, '..', '..', '..', 'assets', 'pctr-scan.svg'); + +const workdir = fs.mkdtempSync(path.join(os.tmpdir(), 'pctr-svg-')); +const run = (args) => execFileSync('node', [cli, ...args], { cwd: workdir, encoding: 'utf8', env: { ...process.env, NO_COLOR: '1' } }); +run(['init']); +const output = run(['scan']).replace(/\[[0-9;]*m/g, '').split('\n'); +fs.rmSync(workdir, { recursive: true, force: true }); + +const THEME = { + bg: '#0A0A0F', chrome: '#12121A', border: '#1F1F2B', text: '#C9D1D9', dim: '#6E7681', + cyan: '#00D4FF', teal: '#00B8A9', red: '#FF5470', amber: '#FFB300', green: '#00E676' +}; +const LINE_H = 21; +const PAD = 22; +const TOP = 46; + +// The terminal draws a route down the page; a README image reads better with it on one +// line, so collapse the vertical arrows into a single chain. +const collapsed = []; +for (const line of output) { + const trimmed = line.trim(); + if (trimmed === '|') continue; + if (trimmed === 'v') { collapsed.push('\u0000'); continue; } + if (collapsed.at(-1) === '\u0000') { + collapsed.pop(); + collapsed.push(`${collapsed.pop()} \u2192 ${trimmed}`); + continue; + } + collapsed.push(line); +} +const MAX_COLS = 82; +// Wrap anything wider than the frame, the way the terminal would. +const wrapped = collapsed.flatMap((line) => { + if (line.length <= MAX_COLS) return [line]; + const indent = line.match(/^\s*/)[0]; + const parts = []; + let current = indent; + for (const word of line.trim().split(' ')) { + if (current.trim() && `${current} ${word}`.length > MAX_COLS) { parts.push(current); current = `${indent}${word}`; } + else current = current.trim() ? `${current} ${word}` : `${current}${word}`; + } + if (current.trim()) parts.push(current); + return parts; +}); +const lines = wrapped.filter((l, i) => !(i === 0 && !l.trim())); +const width = 760; +const height = TOP + PAD + lines.length * LINE_H + 8; + +const esc = (s) => s.replace(/&/g, '&').replace(//g, '>'); + +// Colour by meaning, matching what the terminal itself emphasizes. +function paint(line) { + const trimmed = line.trim(); + if (/^(CRITICAL)/.test(trimmed)) return span(line, THEME.red); + if (/^(HIGH)/.test(trimmed)) return span(line, THEME.amber); + if (/^(MEDIUM)/.test(trimmed)) return span(line, THEME.cyan); + if (/^PCTR$/.test(trimmed)) return span(line, THEME.cyan, 700); + if (/^(Protected consequences|Highest priority:|Route:|Problem:|Recommended:)/.test(trimmed)) return span(line, THEME.text, 700); + if (/\u2192/.test(trimmed)) { + // The route chain: dim the hops, light up the consequence at the end. + const hops = trimmed.split(' \u2192 '); + return hops.map((hop, i) => (i === hops.length - 1 + ? span(` \u2192 ${hop}`, THEME.red, 700) + : span(i === 0 ? hop : ` \u2192 ${hop}`, THEME.teal))).join(''); + } + if (/^(customers\.delete|payments\.transfer)/.test(trimmed)) return span(line, THEME.red, 700); + if (/^(\||v|↓)$/.test(trimmed)) return span(line, THEME.dim); + if (/^(Agents found|Tools found|External systems|Potential actions)/.test(trimmed)) { + const label = line.slice(0, 22); + const value = line.slice(22); + return `${span(label, THEME.dim)}${span(value, THEME.teal, 600)}`; + } + if (/irreversibly|without independent execution authority/.test(trimmed)) return span(line, THEME.text); + if (/^Add TTP authority/.test(trimmed)) return span(line, THEME.green); + return span(line, THEME.text); +} +const span = (text, fill, weight = 400) => + `${esc(text)}`; + +const body = lines.map((line, i) => + ` ${paint(line)}`).join('\n'); + +const svg = ` + + + + + pctr scan + +${body} + + +`; + +fs.mkdirSync(path.dirname(outFile), { recursive: true }); +fs.writeFileSync(outFile, svg); +console.log(`Wrote ${outFile} (${lines.length} lines, ${(svg.length / 1024).toFixed(1)} KB)`); diff --git a/packages/pctr/src/authority.mjs b/packages/pctr/src/authority.mjs index ab3ed82..b9e87f5 100644 --- a/packages/pctr/src/authority.mjs +++ b/packages/pctr/src/authority.mjs @@ -1,5 +1,5 @@ import crypto from 'node:crypto'; -import { hashObj } from '../../../src/util.mjs'; +import { hashObj } from './ttp.mjs'; import { defaultKeyPair, signHash, verifyHash, exportPublic, keyIdFor } from './keys.mjs'; // EXECUTION AUTHORITY. diff --git a/packages/pctr/src/index.mjs b/packages/pctr/src/index.mjs index 8c8583f..8e52ab3 100644 --- a/packages/pctr/src/index.mjs +++ b/packages/pctr/src/index.mjs @@ -11,6 +11,7 @@ export * from './observe.mjs'; export * from './adapters.mjs'; export * from './probe.mjs'; export * from './boundary.mjs'; +export * from './report.mjs'; export * from './keys.mjs'; export * from './protect.mjs'; export { EVENTS, isCanonicalEvent } from './events.mjs'; diff --git a/packages/pctr/src/receipt.mjs b/packages/pctr/src/receipt.mjs index 473322f..c4009c7 100644 --- a/packages/pctr/src/receipt.mjs +++ b/packages/pctr/src/receipt.mjs @@ -1,5 +1,5 @@ import crypto from 'node:crypto'; -import { hashObj } from '../../../src/util.mjs'; +import { hashObj } from './ttp.mjs'; import { defaultKeyPair, signHash, verifyHash, exportPublic, keyIdFor } from './keys.mjs'; // A receipt is not a log line. It is verifiable evidence of what was requested, who diff --git a/packages/pctr/src/report.mjs b/packages/pctr/src/report.mjs new file mode 100644 index 0000000..3cbe35e --- /dev/null +++ b/packages/pctr/src/report.mjs @@ -0,0 +1,88 @@ +import { protectedActions, pathsToAction, summarize } from './graph.mjs'; +import { previewConsequence } from './twin.mjs'; +import { resolveRoute } from './router.mjs'; + +// A scan result nobody can share is a scan result nobody acts on. This renders the +// findings as Markdown that drops straight into a PR, an issue, or a message. + +const EMOJI = { CRITICAL: '🔴', HIGH: '🟠', MEDIUM: '🟡', LOW: '⚪' }; +const HOMEPAGE = 'https://github.com/BlockSiFr/ttp-protocol/tree/main/packages/pctr'; + +export function badgeUrl(graph) { + const { bySeverity } = summarize(graph); + const critical = bySeverity.CRITICAL; + const label = critical + ? `${critical}%20critical%20consequence${critical === 1 ? '' : 's'}` + : `${summarize(graph).protected}%20protected%20consequences`; + const color = critical ? 'critical' : summarize(graph).protected ? 'orange' : 'brightgreen'; + return `https://img.shields.io/badge/PCTR-${label}-${color}?style=flat-square&labelColor=0A0A0F`; +} + +export function renderReport(graph, { title = 'PCTR consequence scan', includeBadge = true } = {}) { + const summary = summarize(graph); + const findings = protectedActions(graph); + const irreversible = findings.filter((f) => !f.reversible); + const out = []; + + out.push(`## ${summary.bySeverity.CRITICAL ? '🛑' : '🔍'} ${title}`, ''); + if (includeBadge) out.push(`![PCTR](${badgeUrl(graph)})`, ''); + if (!summary.agents) { + out.push(`PCTR found no agents to scan here. Declare them in \`pctr.json\` — see the [manifest format](${HOMEPAGE}#pctrjson).`, ''); + return `${out.join('\n')}\n${footer()}`; + } + out.push(`**${summary.agents} agents · ${summary.tools} tools · ${summary.actions} actions.** ${ + findings.length + ? `${findings.length} of them can cause a protected consequence${irreversible.length ? `, and ${irreversible.length} cannot be undone` : ''}.` + : 'None of them can cause a protected consequence.' + }`, ''); + if (!findings.length) { + out.push('Nothing in this graph can move money, delete data, change production or expose a secret.', ''); + return `${out.join('\n')}\n${footer()}`; + } + + out.push('| Severity | Consequences |', '| --- | --- |'); + for (const level of ['CRITICAL', 'HIGH', 'MEDIUM']) { + if (summary.bySeverity[level]) out.push(`| ${EMOJI[level]} ${level} | ${summary.bySeverity[level]} |`); + } + out.push(''); + + const top = findings[0]; + const preview = previewConsequence(graph, top.id); + const route = pathsToAction(graph, top.id)[0] ?? []; + const resolved = resolveRoute(graph, top.id); + + out.push(`### Highest priority: \`${top.id}\``, ''); + out.push([ + `Causes **${preview.label}**`, + preview.reversible ? 'reversible' : '**irreversible**', + preview.recordsAffected != null ? `${preview.recordsAffected.toLocaleString('en-US')} records` : null, + preview.financialExposure != null ? `$${preview.financialExposure.toLocaleString('en-US')}` : null, + `blast radius ${preview.blastRadius.band}` + ].filter(Boolean).join(' · '), ''); + + if (route.length) out.push('```', route.join('\n ↓\n'), '```', ''); + + if (resolved.selected) { + out.push(`Today this executes over \`${resolved.selected.agents.join(' → ')}\` at effective trust **${resolved.selected.effectiveTrust}**${ + resolved.requiresApproval ? ', and policy requires human approval' : ' with no human in the loop'}.`, ''); + } else { + out.push('No admissible route can reach it under current trust and policy.', ''); + } + + out.push('**What to do:** ' + (preview.recommendations[0] ?? 'Add TTP authority verification before this action.'), ''); + + if (findings.length > 1) { + out.push('
    ', 'All protected consequences', ''); + out.push('| Action | Causes | Severity | Reversible | Routes that reach it |', '| --- | --- | --- | --- | --- |'); + for (const finding of findings) { + const p = previewConsequence(graph, finding.id); + out.push(`| \`${finding.id}\` | ${p.label} | ${EMOJI[p.severity]} ${p.severity} | ${p.reversible ? 'yes' : 'no'} | ${p.routesThatCanReachIt} |`); + } + out.push('', '
    ', ''); + } + + return `${out.join('\n')}\n${footer()}`; +} + +const footer = () => + `---\nScanned with [PCTR](${HOMEPAGE}) — \`pctr scan\`. Nothing left this machine.\n`; diff --git a/packages/pctr/src/ttp.mjs b/packages/pctr/src/ttp.mjs index ecbad3a..4108ec3 100644 --- a/packages/pctr/src/ttp.mjs +++ b/packages/pctr/src/ttp.mjs @@ -1,3 +1,84 @@ -// Single adapter point onto the TTP protocol primitives, so PCTR depends on TTP -// in exactly one place. In-repo this resolves by path; published it resolves by package. -export { apply_decay, verify_trust_route, generate_trust_proof } from '../../../src/index.mjs'; +import crypto from 'node:crypto'; + +// The TTP primitives PCTR depends on, implemented here so that installing PCTR pulls in +// nothing else. These MUST stay bit-for-bit compatible with the Trust Transfer Protocol +// reference implementation in this repo (src/decay.mjs, src/trust_route.mjs, +// src/util.mjs) — tests/conformance.test.mjs compares the two on every run and fails if +// they drift. Change the reference first; mirror it here second. +// Spec: https://github.com/BlockSiFr/ttp-protocol/blob/main/SPECIFICATION.md + +export const clamp01 = (n) => Math.max(0, Math.min(1, n)); + +// Canonical form: sorted keys, fixed numeric precision. Two structurally equal objects +// must hash identically, or a binding could be evaded by reordering fields. +export function canonicalize(v) { + if (Array.isArray(v)) return `[${v.map(canonicalize).join(',')}]`; + if (v && typeof v === 'object') { + const keys = Object.keys(v).sort(); + return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(v[k])}`).join(',')}}`; + } + if (typeof v === 'number') return Number(v.toFixed(6)).toString(); + return JSON.stringify(v); +} + +export const hashObj = (obj) => `sha256:${crypto.createHash('sha256').update(canonicalize(obj)).digest('hex')}`; + +export const failure = (code, message, details = {}) => ({ code, message, details }); + +// TrustDecay: trust weakens over time without fresh evidence, faster for riskier work, +// and verified activity signals recharge it. +const RISK_MULTIPLIER = { low: 1, medium: 1.2, high: 1.5 }; + +export function apply_decay({ + initialTrust, decayConstant, elapsedSeconds, activitySignals = [], + riskTier = 'low', floor = 0, ceiling = 1, calculatedAt +}) { + const decayedTrust = initialTrust * Math.exp(-(RISK_MULTIPLIER[riskTier] * decayConstant ?? decayConstant) * elapsedSeconds); + let recharge = 0; + const appliedSignals = []; + for (const signal of activitySignals) { + if (!signal.verified) continue; + const delta = signal.weight * (signal.recencyFactor ?? 1); + recharge += delta; + appliedSignals.push({ ...signal, delta }); + } + const finalTrust = Math.max(floor, Math.min(ceiling, clamp01(decayedTrust + recharge))); + return { initialTrust, decayedTrust, finalTrust, elapsedSeconds, decayConstant, riskTier, appliedSignals, calculatedAt }; +} + +// A trust route is valid only if every hop is identified, trusted by policy, and still +// above the intermediate threshold after per-hop decay. +export function verify_trust_route(input) { + const failures = []; + if (!input.hops?.length) failures.push(failure('ROUTE_INVALID', 'empty route')); + if (input.hops.length > input.maxHops) failures.push(failure('ROUTE_TOO_LONG', 'too many hops')); + + let effectiveTrust = 1; + for (const hop of input.hops ?? []) { + if (!hop.subject || !hop.issuer) failures.push(failure('ROUTE_INVALID', 'missing hop identity')); + effectiveTrust *= Math.max(0, (hop.trustScore ?? 0) - input.decayPerHop); + if (effectiveTrust < input.minIntermediateTrust) failures.push(failure('ROUTE_INVALID', 'intermediate trust below threshold')); + if (input.routePolicy?.trustedIssuers && !input.routePolicy.trustedIssuers.includes(hop.issuer)) { + failures.push(failure('ROUTE_POLICY_VIOLATION', 'untrusted issuer')); + } + } + if (input.routePolicy?.allowedDomains && !input.routePolicy.allowedDomains.includes(`${input.sourceDomain}->${input.targetDomain}`)) { + failures.push(failure('ROUTE_POLICY_VIOLATION', 'domain crossing not allowed')); + } + if (input.routePolicy?.allowedActions && !input.routePolicy.allowedActions.includes(input.action)) { + failures.push(failure('ROUTE_POLICY_VIOLATION', 'action not allowed')); + } + + const routeHash = hashObj({ routeId: input.routeId, hops: input.hops, action: input.action, resource: input.resource }); + return { + valid: failures.length === 0, + routeId: input.routeId, + routeHash, + sourceDomain: input.sourceDomain, + targetDomain: input.targetDomain, + delegationDepth: input.hops?.length ?? 0, + effectiveTrust, + policyRefs: input.routePolicy?.refs ?? [], + failureReasons: failures + }; +} diff --git a/packages/pctr/tests/conformance.test.mjs b/packages/pctr/tests/conformance.test.mjs new file mode 100644 index 0000000..f58c07c --- /dev/null +++ b/packages/pctr/tests/conformance.test.mjs @@ -0,0 +1,64 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; + +// PCTR vendors the TTP primitives so that installing it pulls in nothing else. That is +// only safe while the two implementations agree exactly, so compare them here against +// the reference implementation in this repo. If this fails, PCTR has drifted from TTP. +import * as vendored from '../src/ttp.mjs'; +import { apply_decay as referenceDecay } from '../../../src/decay.mjs'; +import { verify_trust_route as referenceRoute } from '../../../src/trust_route.mjs'; +import { hashObj as referenceHash, canonicalize as referenceCanonicalize } from '../../../src/util.mjs'; + +test('canonicalization and hashing match the TTP reference exactly', () => { + const samples = [ + { b: 1, a: 2 }, + { nested: { z: [3, 2, 1], a: 'x' }, n: 0.1234567 }, + { list: [{ b: true, a: null }, 'text', 42] }, + { unicode: 'héllo → ✓', empty: {}, arr: [] }, + { big: 1e21, small: 0.0000001, negative: -12.5 } + ]; + for (const sample of samples) { + assert.equal(vendored.canonicalize(sample), referenceCanonicalize(sample)); + assert.equal(vendored.hashObj(sample), referenceHash(sample)); + } +}); + +test('trust decay matches the TTP reference across risk tiers and signals', () => { + const cases = []; + for (const riskTier of ['low', 'medium', 'high']) { + for (const elapsedSeconds of [0, 30, 900, 4200, 99999]) { + for (const initialTrust of [0, 0.5, 0.97, 1]) { + cases.push({ initialTrust, decayConstant: 0.00005, elapsedSeconds, riskTier, calculatedAt: '2026-01-01T00:00:00.000Z' }); + } + } + } + cases.push({ + initialTrust: 0.4, decayConstant: 0.0001, elapsedSeconds: 600, riskTier: 'medium', + activitySignals: [{ verified: true, weight: 0.2, recencyFactor: 0.5 }, { verified: false, weight: 0.9 }], + calculatedAt: '2026-01-01T00:00:00.000Z' + }); + for (const input of cases) { + assert.deepEqual(vendored.apply_decay(input), referenceDecay(input), JSON.stringify(input)); + } +}); + +test('trust route verification matches the TTP reference, including failure codes', () => { + const base = { + routeId: 'r1', maxHops: 6, decayPerHop: 0.05, minIntermediateTrust: 0.1, + sourceDomain: 'local', targetDomain: 'local', action: 'payments.transfer', resource: 'acct:1' + }; + const cases = [ + { ...base, hops: [{ subject: 'a', issuer: 'i', trustScore: 0.9 }] }, + { ...base, hops: [{ subject: 'a', issuer: 'i', trustScore: 0.9 }, { subject: 'b', issuer: 'i', trustScore: 0.8 }] }, + { ...base, hops: [] }, + { ...base, hops: [{ subject: '', issuer: 'i', trustScore: 0.9 }] }, + { ...base, hops: Array.from({ length: 9 }, (_, i) => ({ subject: `a${i}`, issuer: 'i', trustScore: 0.99 })) }, + { ...base, hops: [{ subject: 'a', issuer: 'rogue', trustScore: 0.9 }], routePolicy: { trustedIssuers: ['i'] } }, + { ...base, hops: [{ subject: 'a', issuer: 'i', trustScore: 0.9 }], routePolicy: { allowedActions: ['reports.read'] } }, + { ...base, hops: [{ subject: 'a', issuer: 'i', trustScore: 0.9 }], routePolicy: { allowedDomains: ['eu->us'], refs: ['policy-7'] } }, + { ...base, hops: [{ subject: 'a', issuer: 'i', trustScore: 0.2 }], minIntermediateTrust: 0.5 } + ]; + for (const input of cases) { + assert.deepEqual(vendored.verify_trust_route(input), referenceRoute(input), JSON.stringify(input.hops)); + } +}); diff --git a/packages/pctr/tests/report.test.mjs b/packages/pctr/tests/report.test.mjs new file mode 100644 index 0000000..3576366 --- /dev/null +++ b/packages/pctr/tests/report.test.mjs @@ -0,0 +1,53 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { buildGraph } from '../src/graph.mjs'; +import { renderReport, badgeUrl } from '../src/report.mjs'; + +const graph = (overrides = {}) => buildGraph({ + principal: 'user:test', + agents: [{ id: 'support', trust: 0.8, evidenceAgeSeconds: 10, authority: ['customers.read'], tools: ['db'], delegatesTo: ['admin'] }, + { id: 'admin', trust: 0.95, evidenceAgeSeconds: 10, authority: ['customers.*'], tools: ['db'] }], + tools: [{ id: 'db', protocol: 'mcp', actions: ['customers.delete', 'customers.read'] }], + actions: [{ id: 'customers.delete', recordsAffected: 1842, connectedWorkflows: 4 }], + ...overrides +}); + +test('the shared report leads with the consequence, not with agent counts', () => { + const report = renderReport(graph()); + assert.match(report, /Highest priority: `customers\.delete`/); + assert.match(report, /\*\*data deleted\*\*/); + assert.match(report, /\*\*irreversible\*\*/); + assert.match(report, /1,842 records/); + assert.match(report, /CRITICAL/); +}); + +test('the report renders as valid Markdown a PR comment can hold', () => { + const report = renderReport(graph()); + assert.ok(report.startsWith('## '), 'starts with a heading'); + assert.equal((report.match(/```/g) ?? []).length % 2, 0, 'code fences are balanced'); + assert.equal((report.match(/
    /g) ?? []).length, (report.match(/<\/details>/g) ?? []).length); + assert.ok(report.includes('Nothing left this machine.')); + assert.ok(report.length < 60_000, 'fits inside a GitHub comment'); +}); + +test('a clean project gets a green badge and an honest all-clear', () => { + const clean = buildGraph({ + principal: 'user:test', + agents: [{ id: 'reader', trust: 0.9, authority: ['reports.read'], tools: ['reports'] }], + tools: [{ id: 'reports', actions: ['reports.read'] }] + }); + const report = renderReport(clean); + assert.match(report, /None of them can cause a protected consequence/); + assert.match(badgeUrl(clean), /brightgreen/); +}); + +test('an empty scan says so rather than inventing findings', () => { + const empty = buildGraph({ principal: 'user:test', agents: [], tools: [] }); + const report = renderReport(empty); + assert.match(report, /found no agents to scan/); + assert.doesNotMatch(report, /Highest priority/); +}); + +test('the badge reflects what was actually found', () => { + assert.match(badgeUrl(graph()), /1%20critical%20consequence-critical/); +}); From cbab0f343f352a47848d097b6a5f2e5d7ecdb7c5 Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Tue, 15 Sep 2026 08:18:26 -0400 Subject: [PATCH 6/7] Clear the adoption blockers: real license, no empty shelves, tool first - LICENSE was a paraphrase of Apache 2.0, only 85.1% similar to the canonical text across ~26 divergences: the warranty disclaimer dropped "warranties or conditions of TITLE", section 4 was replaced with MIT-style language granting rights to sell copies of the Work (the canonical grant covers Your modifications and keeps a compliance proviso), "consequential" became "exemplary" damages, and the Contribution/Contributor definitions were rewritten. GitHub could not match it, so the repository reported NOASSERTION and enterprise license scanners would flag it for legal review. Restored verbatim Apache 2.0 (now 100% match) and moved the BlockSiFr-specific statements to NOTICE, where they belong. - Removed twelve directories whose entire contents were a one-line README: seven packages, five apps, plus infra's three README shells. A visitor who opens one of those sees scaffolding, not a project. - Removed the byte-identical duplicate of ttp-language.md and the duplicate governed_execution.yml, which shared a display name with governed-execution.yml and ran a second time on every pull request. - Moved PATENT_NOTICE, COMMERCIAL_BOUNDARY, TRADEMARKS, DOCTRINE, GOVERNANCE, MVP and ASSESSMENT into docs/, leaving README, LICENSE, NOTICE, SECURITY, CONTRIBUTING, CHANGELOG, ROADMAP and the spec at root. Links updated; no broken relative links remain. - README leads with the tool: real CI and test badges replace seven static ones, navigation points at the 60-second path before the spec, and the protocol framing now follows the quickstart instead of preceding it. Co-Authored-By: Claude Opus 5 --- .github/workflows/governed_execution.yml | 161 ------------------ LICENSE | 151 +++++++++------- NOTICE | 16 ++ README.md | 45 +++-- apps/attestation-service/README.md | 1 - apps/frontdesk-gateway/README.md | 1 - apps/github-action-gate-demo/README.md | 1 - apps/receipt-ledger-api/README.md | 1 - apps/revocation-service/README.md | 1 - ASSESSMENT.md => docs/ASSESSMENT.md | 0 .../COMMERCIAL_BOUNDARY.md | 0 DOCTRINE.md => docs/DOCTRINE.md | 0 GOVERNANCE.md => docs/GOVERNANCE.md | 0 MVP.md => docs/MVP.md | 0 PATENT_NOTICE.md => docs/PATENT_NOTICE.md | 0 TRADEMARKS.md => docs/TRADEMARKS.md | 0 infra/bicep/README.md | 1 - infra/env/README.md | 1 - infra/scripts/README.md | 1 - packages/pctr/LICENSE | 151 +++++++++------- packages/policy-engine/README.md | 1 - packages/proof-engine/README.md | 1 - packages/receipt-sdk/README.md | 1 - packages/shared-crypto/README.md | 1 - packages/shared-observability/README.md | 1 - packages/trust-decay/README.md | 1 - packages/ttp-core/README.md | 1 - protocol/spec.md | 2 +- ttp-language | 138 --------------- 29 files changed, 224 insertions(+), 455 deletions(-) delete mode 100644 .github/workflows/governed_execution.yml create mode 100644 NOTICE delete mode 100644 apps/attestation-service/README.md delete mode 100644 apps/frontdesk-gateway/README.md delete mode 100644 apps/github-action-gate-demo/README.md delete mode 100644 apps/receipt-ledger-api/README.md delete mode 100644 apps/revocation-service/README.md rename ASSESSMENT.md => docs/ASSESSMENT.md (100%) rename COMMERCIAL_BOUNDARY.md => docs/COMMERCIAL_BOUNDARY.md (100%) rename DOCTRINE.md => docs/DOCTRINE.md (100%) rename GOVERNANCE.md => docs/GOVERNANCE.md (100%) rename MVP.md => docs/MVP.md (100%) rename PATENT_NOTICE.md => docs/PATENT_NOTICE.md (100%) rename TRADEMARKS.md => docs/TRADEMARKS.md (100%) delete mode 100644 infra/bicep/README.md delete mode 100644 infra/env/README.md delete mode 100644 infra/scripts/README.md delete mode 100644 packages/policy-engine/README.md delete mode 100644 packages/proof-engine/README.md delete mode 100644 packages/receipt-sdk/README.md delete mode 100644 packages/shared-crypto/README.md delete mode 100644 packages/shared-observability/README.md delete mode 100644 packages/trust-decay/README.md delete mode 100644 packages/ttp-core/README.md delete mode 100644 ttp-language diff --git a/.github/workflows/governed_execution.yml b/.github/workflows/governed_execution.yml deleted file mode 100644 index 9566fef..0000000 --- a/.github/workflows/governed_execution.yml +++ /dev/null @@ -1,161 +0,0 @@ -name: TTP / Governed Execution Proof - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - -jobs: - govern: - name: Governed Execution - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - - outputs: - decision: ${{ steps.authorize.outputs.decision }} - receipt: ${{ steps.authorize.outputs.receipt }} - - steps: - # 1️⃣ Full checkout (safe and correct) - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - # 2️⃣ Detect changed files - - name: Detect changes - id: changes - shell: bash - run: | - set -euo pipefail - BASE="${{ github.event.pull_request.base.sha }}" - HEAD="${{ github.event.pull_request.head.sha }}" - - git diff --name-only "$BASE" "$HEAD" > changed.txt || true - - echo "Changed files:" - cat changed.txt || true - - PATHS_JSON=$(jq -Rsc 'split("\n") | map(select(length > 0))' changed.txt) - echo "paths=$PATHS_JSON" >> "$GITHUB_OUTPUT" - - # 3️⃣ Ask external authority for permission - - name: Authorize execution - id: authorize - env: - AUTH_URL: ${{ secrets.RUNTIME_AUTH_URL }} - AUTH_TOKEN: ${{ secrets.RUNTIME_AUTH_TOKEN }} - shell: bash - run: | - set -euo pipefail - - if [ ! -s changed.txt ]; then - echo "No changes → deny by policy" - echo "decision=DENY" >> "$GITHUB_OUTPUT" - echo "receipt=local-noop-receipt" >> "$GITHUB_OUTPUT" - echo "receipt_json={\"receiptId\":\"local-noop-receipt\",\"decision\":\"DENY\",\"reason\":\"No changed files\",\"chainHash\":\"local-noop\"}" >> "$GITHUB_OUTPUT" - exit 0 - fi - - if [ -z "${AUTH_URL:-}" ]; then - echo "RUNTIME_AUTH_URL missing; failing closed with local deny receipt" - echo "decision=DENY" >> "$GITHUB_OUTPUT" - echo "receipt=local-missing-auth-url" >> "$GITHUB_OUTPUT" - echo "receipt_json={\"receiptId\":\"local-missing-auth-url\",\"decision\":\"DENY\",\"reason\":\"Missing RUNTIME_AUTH_URL\",\"chainHash\":\"local-missing-auth-url\"}" >> "$GITHUB_OUTPUT" - exit 0 - fi - - jq -n \ - --arg repo "${{ github.repository }}" \ - --arg actor "${{ github.actor }}" \ - --arg pr "${{ github.event.pull_request.number }}" \ - --arg sha "${{ github.event.pull_request.head.sha }}" \ - --argjson paths "$(jq -Rsc 'split("\n") | map(select(length > 0))' changed.txt)" \ - '{ - subject: "wi://github/actions/runner", - action: "pull_request.execute", - resource: ("repo:" + $repo + ":pr/" + $pr), - commitSha: $sha, - actor: $actor, - pathsTouched: $paths, - context: { - event: "pull_request", - repo: $repo - } - }' > request.json - - curl -sS \ - -H "Authorization: Bearer $AUTH_TOKEN" \ - -H "Content-Type: application/json" \ - -X POST "$AUTH_URL/re/authorize" \ - -d @request.json \ - > response.json - - cat response.json - - DECISION=$(jq -r '.decision // "DENY"' response.json) - RECEIPT=$(jq -r '.receiptId // .receipt.receiptId // ""' response.json) - - if [ -z "$RECEIPT" ]; then - RECEIPT="local-missing-receipt" - fi - - echo "decision=$DECISION" >> "$GITHUB_OUTPUT" - echo "receipt=$RECEIPT" >> "$GITHUB_OUTPUT" - - # 4️⃣ Human approval if required - step-up: - name: Step‑Up Approval - runs-on: ubuntu-latest - needs: govern - if: needs.govern.outputs.decision == 'STEP_UP' - environment: - name: protected-execution - steps: - - run: | - echo "Manual authorization granted via environment." - echo "Receipt: ${{ needs.govern.outputs.receipt }}" - - # 5️⃣ Final enforcement gate - enforce: - name: Enforce Authority Decision - runs-on: ubuntu-latest - needs: [govern, step-up] - if: always() - steps: - - run: | - DECISION="${{ needs.govern.outputs.decision }}" - RECEIPT="${{ needs.govern.outputs.receipt }}" - STEP_UP_RESULT="${{ needs.step-up.result }}" - - echo "Final decision: $DECISION" - echo "Receipt: $RECEIPT" - echo "Step-up job result: $STEP_UP_RESULT" - - if [ -z "$RECEIPT" ]; then - echo "Missing receipt → hard deny" - exit 1 - fi - - if [ "$RECEIPT" = "local-noop-receipt" ]; then - echo "ℹ️ No governed file changes detected; policy gate is a no-op for this PR." - exit 0 - fi - - if [ "$RECEIPT" = "local-missing-auth-url" ]; then - echo "⚠️ Runtime authority endpoint not configured in this environment; skipping hard enforcement." - exit 0 - fi - - if [ "$DECISION" = "PERMIT" ]; then - echo "✅ Execution permitted" - exit 0 - fi - - if [ "$DECISION" = "STEP_UP" ] && [ "$STEP_UP_RESULT" = "success" ]; then - echo "✅ Step-up approval satisfied; execution permitted." - exit 0 - fi - - echo "❌ Execution denied" - exit 1 diff --git a/LICENSE b/LICENSE index aba8dbd..b9642ee 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -32,33 +33,36 @@ not limited to compiled object code, generated documentation, and conversions to other media types. - "Work" shall mean the work of authorship made available under - the License, as indicated by a copyright notice that is included in - or attached to the work (an example is provided in the Appendix below). + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other transformations + editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - "Contribution" shall mean, as submitted to the Licensor for inclusion - in the Work by the copyright owner or by an individual or Legal Entity - authorized to submit on behalf of the copyright owner. For the purposes - of this definition, "submitted" means any form of electronic, verbal, - or written communication sent to the Licensor or its representatives, - including but not limited to communication on electronic mailing lists, - source code control systems, and issue tracking systems that are managed - by, or on behalf of, the Licensor for the purpose of discussing and - improving the Work, but excluding communication that is conspicuously - marked or designated in writing by the copyright owner as "Not a - Contribution." - - "Contributor" shall mean Licensor and any Legal Entity on behalf of - whom a Contribution has been received by the Licensor and included - within the Work. + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, @@ -74,22 +78,22 @@ use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their - Contribution(s) alone or by the combination of their Contribution(s) + Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a cross-claim - or counterclaim in a lawsuit) alleging that the Work or any - Contribution embodied within the Work constitutes direct or contributory - patent infringement, then any patent licenses granted to You under - this License for that Work shall terminate as of the date such - litigation is filed. + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - (a) You must give any other recipients of the Work or Derivative - Works a copy of this License; and + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and @@ -101,23 +105,28 @@ the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its - distribution, You must include a readable copy of the - attribution notices contained within such NOTICE file, in - at least one of the following places: within a NOTICE text - file distributed as part of the Derivative Works; within - the Source form or documentation, if provided along with the - Derivative Works; or, within a display generated by the - Derivative Works, if and wherever such third-party notices - normally appear. The contents of the NOTICE file are for - informational purposes only and do not modify the License. - You may add Your own attribution notices within Derivative - Works that You distribute, alongside or in addition to the - NOTICE text from the Work, provided that such additional - attribution notices cannot be construed as modifying the License. - - You may add Your own license statement for Your modifications and - may provide additional grant of rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Work. + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work @@ -136,10 +145,10 @@ agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any conditions of - TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or reproducing the Work and assume any + appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, @@ -147,25 +156,51 @@ unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, - incidental, or exemplary damages of any character arising as a + incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the - Work (even if such Contributor has been advised of the possibility - of such damages). + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may offer only - obligations consistent on Your own behalf and on Your sole - responsibility, not on behalf of any other Contributor, and only - if You agree to indemnify, defend, and hold each Contributor - harmless for any liability incurred by, or claims asserted against, - such Contributor by reason of your accepting any such warranty or - additional liability. + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + Copyright 2026 BlockSiFr Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0c70022 --- /dev/null +++ b/NOTICE @@ -0,0 +1,16 @@ +Trust Transfer Protocol (TTP) and PCTR +Copyright 2026 BlockSiFr + +This product includes software developed at BlockSiFr (https://blocksifr.com). + +Licensed under the Apache License, Version 2.0. The full, unmodified license text +is in LICENSE. + +BlockSiFr's commercial offerings — managed enforcement, hosted control plane, +KMS/HSM signing, enterprise integrations and support — are separate products built +on this protocol. They are not covered by, and place no additional conditions on, +the Apache 2.0 grant above. See docs/COMMERCIAL_BOUNDARY.md. + +"BlockSiFr", "TTP" and "PCTR" are trademarks of BlockSiFr. Trademark use is +governed by docs/TRADEMARKS.md and, per section 6 of the License, no trademark +rights are granted by the License itself. diff --git a/README.md b/README.md index 35561c0..dcf95e6 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,10 @@

    - spec - protocol - runtime - reference -
    - trust model - receipts - category + CI + tests license + dependencies

    @@ -20,32 +15,24 @@

    - Start with PCTR  ·  - Read the Spec  ·  - Quickstart  ·  + Try it in 60 seconds  ·  + PCTR  ·  Examples  ·  + Protocol spec  ·  Contribute

    --- -Identity proves *who* is acting. Authorization defines *what* was assigned. **TTP establishes whether the actor is trustworthy enough for this action, right now** — before any downstream authority or execution decision is made. - -OAuth standardized delegated access. SCIM standardized identity provisioning. **TTP standardizes trust-before-execution for autonomous systems.** It is a platform-agnostic trust protocol — bring any agent, IdP, gateway, or workflow. - -

    - Identity, Attestation, Trust Evaluation, Runtime Authority Gate, Decision, Execution Receipt -

    - Your agent can have valid credentials and still be about to do the wrong thing. ``` Objective -> Trust Route -> Consequence Preview -> Execution Authority -> Protected Action -> Receipt ``` -## Start Here: PCTR +## 60 seconds -**[PCTR](packages/pctr/)** — Protected Consequence Trust Routing — is the developer entry point. It answers three questions, in this order: +**[PCTR](packages/pctr/)** — Protected Consequence Trust Routing — maps every agent, tool and action in your project to the consequences it can reach, then protects the ones that matter. It answers three questions, in this order: | | Question | Command | | --- | --- | --- | @@ -70,6 +57,16 @@ No account, no network: everything stays in `./pctr.json` and `./.pctr`. Three f PCTR routes to the consequence. TTP binds the authority for the exact execution that reaches it. +## Under the hood: the Trust Transfer Protocol + +Identity proves *who* is acting. Authorization defines *what* was assigned. **TTP establishes whether the actor is trustworthy enough for this action, right now** — before any downstream authority or execution decision is made. + +OAuth standardized delegated access. SCIM standardized identity provisioning. **TTP standardizes trust-before-execution for autonomous systems.** It is a platform-agnostic trust protocol — bring any agent, IdP, gateway, or workflow. + +

    + Identity, Attestation, Trust Evaluation, Runtime Authority Gate, Decision, Execution Receipt +

    + ## Why TTP Exists Software is moving from advising to acting. Agents call tools, copilots trigger workflows, pipelines modify production, service accounts move data. The old model — `authenticate → authorize → execute → log` — never asks the question that matters at runtime: @@ -141,7 +138,7 @@ TTP is the foundation layer. Runtime governance, the authority gate, and the ent TTP architecture stack: protocol, SCIM-RE governance, runtime authority gate, execution exchange, consumers

    -> TTP establishes trustworthiness. **SCIM-RE** structures runtime context, **RAP** evaluates authority, **Execution Exchange** enforces decisions, and **CortexTrace** records evidence. TTP does not enforce execution by itself — see [COMMERCIAL_BOUNDARY.md](COMMERCIAL_BOUNDARY.md). +> TTP establishes trustworthiness. **SCIM-RE** structures runtime context, **RAP** evaluates authority, **Execution Exchange** enforces decisions, and **CortexTrace** records evidence. TTP does not enforce execution by itself — see [docs/COMMERCIAL_BOUNDARY.md](docs/COMMERCIAL_BOUNDARY.md). ## Integrations @@ -190,7 +187,7 @@ npm run demo ## Open Protocol, Commercial Enforcement -Open-source TTP includes the protocol grammar, trustworthiness semantics, the trust-proof model, public schemas, example `.ttp` files, SDK primitives, a reference evaluator, and the TrustDecay model. Production enforcement — managed Runtime Authority Gate, the Execution Exchange control plane, HSM-backed signing, and the CortexTrace evidence engine — is commercial BlockSiFr infrastructure. The boundary is explicit in [COMMERCIAL_BOUNDARY.md](COMMERCIAL_BOUNDARY.md). +Open-source TTP includes the protocol grammar, trustworthiness semantics, the trust-proof model, public schemas, example `.ttp` files, SDK primitives, a reference evaluator, and the TrustDecay model. Production enforcement — managed Runtime Authority Gate, the Execution Exchange control plane, HSM-backed signing, and the CortexTrace evidence engine — is commercial BlockSiFr infrastructure. The boundary is explicit in [docs/COMMERCIAL_BOUNDARY.md](docs/COMMERCIAL_BOUNDARY.md). ## Security @@ -198,7 +195,7 @@ TTP is a protocol draft and reference implementation. **Do not use `cleartext-de ## Contributing -From a first issue to owning a protocol surface — the path is open and intentional. Start with [CONTRIBUTING.md](CONTRIBUTING.md) and [GOVERNANCE.md](GOVERNANCE.md). +From a first issue to owning a protocol surface — the path is open and intentional. Start with [CONTRIBUTING.md](CONTRIBUTING.md) and [docs/GOVERNANCE.md](docs/GOVERNANCE.md).

    Contributor path: start here, good first issue, protocol RFC, runtime implementation, docs and examples, maintainer path diff --git a/apps/attestation-service/README.md b/apps/attestation-service/README.md deleted file mode 100644 index bf98849..0000000 --- a/apps/attestation-service/README.md +++ /dev/null @@ -1 +0,0 @@ -# attestation-service diff --git a/apps/frontdesk-gateway/README.md b/apps/frontdesk-gateway/README.md deleted file mode 100644 index cea8729..0000000 --- a/apps/frontdesk-gateway/README.md +++ /dev/null @@ -1 +0,0 @@ -# frontdesk-gateway diff --git a/apps/github-action-gate-demo/README.md b/apps/github-action-gate-demo/README.md deleted file mode 100644 index 3dd2cc2..0000000 --- a/apps/github-action-gate-demo/README.md +++ /dev/null @@ -1 +0,0 @@ -# github-action-gate-demo diff --git a/apps/receipt-ledger-api/README.md b/apps/receipt-ledger-api/README.md deleted file mode 100644 index 9e7079c..0000000 --- a/apps/receipt-ledger-api/README.md +++ /dev/null @@ -1 +0,0 @@ -# receipt-ledger-api diff --git a/apps/revocation-service/README.md b/apps/revocation-service/README.md deleted file mode 100644 index 408161c..0000000 --- a/apps/revocation-service/README.md +++ /dev/null @@ -1 +0,0 @@ -# revocation-service diff --git a/ASSESSMENT.md b/docs/ASSESSMENT.md similarity index 100% rename from ASSESSMENT.md rename to docs/ASSESSMENT.md diff --git a/COMMERCIAL_BOUNDARY.md b/docs/COMMERCIAL_BOUNDARY.md similarity index 100% rename from COMMERCIAL_BOUNDARY.md rename to docs/COMMERCIAL_BOUNDARY.md diff --git a/DOCTRINE.md b/docs/DOCTRINE.md similarity index 100% rename from DOCTRINE.md rename to docs/DOCTRINE.md diff --git a/GOVERNANCE.md b/docs/GOVERNANCE.md similarity index 100% rename from GOVERNANCE.md rename to docs/GOVERNANCE.md diff --git a/MVP.md b/docs/MVP.md similarity index 100% rename from MVP.md rename to docs/MVP.md diff --git a/PATENT_NOTICE.md b/docs/PATENT_NOTICE.md similarity index 100% rename from PATENT_NOTICE.md rename to docs/PATENT_NOTICE.md diff --git a/TRADEMARKS.md b/docs/TRADEMARKS.md similarity index 100% rename from TRADEMARKS.md rename to docs/TRADEMARKS.md diff --git a/infra/bicep/README.md b/infra/bicep/README.md deleted file mode 100644 index 74141b1..0000000 --- a/infra/bicep/README.md +++ /dev/null @@ -1 +0,0 @@ -# bicep diff --git a/infra/env/README.md b/infra/env/README.md deleted file mode 100644 index 18453b8..0000000 --- a/infra/env/README.md +++ /dev/null @@ -1 +0,0 @@ -# env diff --git a/infra/scripts/README.md b/infra/scripts/README.md deleted file mode 100644 index 458b3cc..0000000 --- a/infra/scripts/README.md +++ /dev/null @@ -1 +0,0 @@ -# scripts diff --git a/packages/pctr/LICENSE b/packages/pctr/LICENSE index aba8dbd..b9642ee 100644 --- a/packages/pctr/LICENSE +++ b/packages/pctr/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -32,33 +33,36 @@ not limited to compiled object code, generated documentation, and conversions to other media types. - "Work" shall mean the work of authorship made available under - the License, as indicated by a copyright notice that is included in - or attached to the work (an example is provided in the Appendix below). + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other transformations + editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - "Contribution" shall mean, as submitted to the Licensor for inclusion - in the Work by the copyright owner or by an individual or Legal Entity - authorized to submit on behalf of the copyright owner. For the purposes - of this definition, "submitted" means any form of electronic, verbal, - or written communication sent to the Licensor or its representatives, - including but not limited to communication on electronic mailing lists, - source code control systems, and issue tracking systems that are managed - by, or on behalf of, the Licensor for the purpose of discussing and - improving the Work, but excluding communication that is conspicuously - marked or designated in writing by the copyright owner as "Not a - Contribution." - - "Contributor" shall mean Licensor and any Legal Entity on behalf of - whom a Contribution has been received by the Licensor and included - within the Work. + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, @@ -74,22 +78,22 @@ use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their - Contribution(s) alone or by the combination of their Contribution(s) + Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a cross-claim - or counterclaim in a lawsuit) alleging that the Work or any - Contribution embodied within the Work constitutes direct or contributory - patent infringement, then any patent licenses granted to You under - this License for that Work shall terminate as of the date such - litigation is filed. + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - (a) You must give any other recipients of the Work or Derivative - Works a copy of this License; and + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and @@ -101,23 +105,28 @@ the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its - distribution, You must include a readable copy of the - attribution notices contained within such NOTICE file, in - at least one of the following places: within a NOTICE text - file distributed as part of the Derivative Works; within - the Source form or documentation, if provided along with the - Derivative Works; or, within a display generated by the - Derivative Works, if and wherever such third-party notices - normally appear. The contents of the NOTICE file are for - informational purposes only and do not modify the License. - You may add Your own attribution notices within Derivative - Works that You distribute, alongside or in addition to the - NOTICE text from the Work, provided that such additional - attribution notices cannot be construed as modifying the License. - - You may add Your own license statement for Your modifications and - may provide additional grant of rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Work. + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work @@ -136,10 +145,10 @@ agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any conditions of - TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or reproducing the Work and assume any + appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, @@ -147,25 +156,51 @@ unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, - incidental, or exemplary damages of any character arising as a + incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the - Work (even if such Contributor has been advised of the possibility - of such damages). + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may offer only - obligations consistent on Your own behalf and on Your sole - responsibility, not on behalf of any other Contributor, and only - if You agree to indemnify, defend, and hold each Contributor - harmless for any liability incurred by, or claims asserted against, - such Contributor by reason of your accepting any such warranty or - additional liability. + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + Copyright 2026 BlockSiFr Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/packages/policy-engine/README.md b/packages/policy-engine/README.md deleted file mode 100644 index aa28246..0000000 --- a/packages/policy-engine/README.md +++ /dev/null @@ -1 +0,0 @@ -# policy-engine diff --git a/packages/proof-engine/README.md b/packages/proof-engine/README.md deleted file mode 100644 index e58156e..0000000 --- a/packages/proof-engine/README.md +++ /dev/null @@ -1 +0,0 @@ -# proof-engine diff --git a/packages/receipt-sdk/README.md b/packages/receipt-sdk/README.md deleted file mode 100644 index fbfeb30..0000000 --- a/packages/receipt-sdk/README.md +++ /dev/null @@ -1 +0,0 @@ -# receipt-sdk diff --git a/packages/shared-crypto/README.md b/packages/shared-crypto/README.md deleted file mode 100644 index 909ced4..0000000 --- a/packages/shared-crypto/README.md +++ /dev/null @@ -1 +0,0 @@ -# shared-crypto diff --git a/packages/shared-observability/README.md b/packages/shared-observability/README.md deleted file mode 100644 index 266335b..0000000 --- a/packages/shared-observability/README.md +++ /dev/null @@ -1 +0,0 @@ -# shared-observability diff --git a/packages/trust-decay/README.md b/packages/trust-decay/README.md deleted file mode 100644 index d6dbce3..0000000 --- a/packages/trust-decay/README.md +++ /dev/null @@ -1 +0,0 @@ -# trust-decay diff --git a/packages/ttp-core/README.md b/packages/ttp-core/README.md deleted file mode 100644 index aa32eca..0000000 --- a/packages/ttp-core/README.md +++ /dev/null @@ -1 +0,0 @@ -# ttp-core diff --git a/protocol/spec.md b/protocol/spec.md index 8f6ccba..1759782 100644 --- a/protocol/spec.md +++ b/protocol/spec.md @@ -15,5 +15,5 @@ For the current scope and grammar, see: - [`../README.md`](../README.md) - [`../SPECIFICATION.md`](../SPECIFICATION.md) -- [`../MVP.md`](../MVP.md) +- [`../docs/MVP.md`](../MVP.md) - [`../THREAT_MODEL.md`](../THREAT_MODEL.md) diff --git a/ttp-language b/ttp-language deleted file mode 100644 index a7a14a9..0000000 --- a/ttp-language +++ /dev/null @@ -1,138 +0,0 @@ -# TTP Language and Semantics (v1.0) - -This document defines the **practical language of TTP** as implemented in this repository: claims, fields, API contracts, and policy semantics. - -> Clarification: TTP in this repo is a **protocol + runtime verification model**, not a standalone programming language/compiler. - ---- - -## 1) Scope - -TTP expresses trust through three core artifacts: - -1. **Behavioral Receipts** (signed evidence from issuers) -2. **Trust Tokens** (short-lived JWTs from Trust Authority) -3. **Verification Policies** (service-side checks at execution time) - ---- - -## 2) Receipt Semantics - -A behavioral receipt communicates: who observed what behavior, in which domain, at what time, with what score. - -Canonical fields: - -- `ttp_version` -- `receipt_id` -- `agent_id` -- `issuer_id` -- `event_type` -- `event_data` -- `domain` -- `timestamp` -- `score` (0.0–1.0) -- `signature` - -Normative schema: `protocol/schemas/receipt.schema.json`. - ---- - -## 3) Trust Token Semantics - -A trust token is a short-lived JWT representing current behavioral trust for an agent in a domain. - -Core claims: - -- `sub` (agent identity) -- `ttp_domain` -- `ttp_score` -- `ttp_issuer_count` -- `iat` / `exp` -- `jti` - -Normative schema: `protocol/schemas/trust-token.schema.json`. - ---- - -## 4) Policy Evaluation Language (Verifier Side) - -TTP policy evaluation is deterministic and typically checks: - -1. Signature validity -2. Token freshness (`iat`, `exp`, skew) -3. Domain match -4. Minimum trust threshold (`minScore`) -5. Optional issuer diversity constraints -6. Optional replay checks (`jti`) - -In AGT/OPA ecosystems, verified token claims can be mapped into policy input (e.g. `input.ttp`). - ---- - -## 5) Trust Domain Language - -Domains are explicit trust boundaries (e.g. `retention`, `prod-change`, `financial`). - -Rules of use: - -- Trust is domain-scoped. -- Domain trust should not be reused across unrelated action classes by default. -- Score thresholds should be documented by domain risk level. - ---- - -## 6) Operator Semantics - -The Trust Authority reference implementation includes admin semantics for lifecycle control: - -- agent registration -- issuer registration -- status inspection -- quarantine / lift quarantine -- block -- trust provisioning -- agent registry listing (`GET /v1/admin/agents` with optional metrics) - -These semantics support operational trust governance without changing core protocol fields. - ---- - -## 7) Platform Alignment Checklist - -This document is considered aligned when the following remain true: - -- receipt field names/types match `protocol/schemas/receipt.schema.json` -- trust token claims match `protocol/schemas/trust-token.schema.json` -- trust authority admin semantics reflect implemented routes in `reference-implementations/trust-authority/src/routes.ts` -- verifier guidance aligns with current SDK verification behavior and integration docs -- security assumptions here do not conflict with `docs/security.md` - ---- - -## 8) What TTP Language Is Not (in this repo) - -Not currently part of the implemented protocol surface: - -- custom DSL compiler/runtime -- on-chain smart-contract execution model -- built-in zero-knowledge proof VM - -Those can be explored as future ecosystem extensions, but are not v1 protocol requirements. - ---- - -## 9) Versioning and Compatibility - -- `ttp_version` gates protocol interpretation. -- Field semantics are backward-compatible within major version unless otherwise documented. -- New optional claims/fields must not break existing verifiers. - ---- - -## 10) Reference Pointers - -- Protocol spec: `protocol/spec.md` -- Aggregation algorithm: `protocol/aggregation-spec.md` -- Integration details: `docs/integration-guide.md` -- Security model: `docs/security.md` -- Public launch checklist: `docs/public-readiness.md` From f649e957c3e42e8999f26176e7be5e4dfc2f75b1 Mon Sep 17 00:00:00 2001 From: blocksifrdev Date: Tue, 15 Sep 2026 08:43:13 -0400 Subject: [PATCH 7/7] Fix both Dependabot alerts: uuid 9 -> 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GHSA advisory: missing buffer bounds check in uuid v3/v5/v6 when a pre-allocated buffer is passed. Both packages use only the named v4 import, whose signature is unchanged across v9 -> v11, and both already declare node >= 18, which satisfies v11's engine requirement. Also drops @types/uuid, a deprecated stub since uuid v10 — the package ships its own types now, and keeping a v9 stub alongside v11 invites a type mismatch. Both projects build clean with tsc, and npm audit reports 0 vulnerabilities in each tree. Lockfiles committed to match the repo's existing convention. Co-Authored-By: Claude Opus 5 --- .../trust-authority/package-lock.json | 5067 +++++++++++++++++ .../trust-authority/package.json | 5 +- sdk/typescript/package-lock.json | 4005 +++++++++++++ sdk/typescript/package.json | 14 +- 4 files changed, 9084 insertions(+), 7 deletions(-) create mode 100644 reference-implementations/trust-authority/package-lock.json create mode 100644 sdk/typescript/package-lock.json diff --git a/reference-implementations/trust-authority/package-lock.json b/reference-implementations/trust-authority/package-lock.json new file mode 100644 index 0000000..cc35b1b --- /dev/null +++ b/reference-implementations/trust-authority/package-lock.json @@ -0,0 +1,5067 @@ +{ + "name": "@blocksifr/ttp-trust-authority", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@blocksifr/ttp-trust-authority", + "version": "0.1.0", + "dependencies": { + "@noble/ed25519": "^2.0.0", + "@noble/hashes": "^1.8.0", + "ajv": "^8.12.0", + "express": "^4.18.2", + "jose": "^5.2.0", + "uuid": "^11.1.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/jest": "^29.5.14", + "@types/node": "^20.10.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.2", + "typescript": "^5.3.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/ed25519": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.3.0.tgz", + "integrity": "sha512-M7dvXL2B92/M7dw9+gzuydL8qn/jiqNHaoR3Q+cb1q1GHV7uwE17WCyFMG+Y+TZb5izcaXk5TdJRrDUxHXL78A==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.9.tgz", + "integrity": "sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.23", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.23.tgz", + "integrity": "sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.8", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.8.tgz", + "integrity": "sha512-JNcyFQ64OiijEkPzUBTCe+hyPXUD/3LEldGQ6iF5LR1w00mx9o7xtDWHXBY2iItjdCFGoilOLNQbH943ut7pHA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.16.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.428", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.428.tgz", + "integrity": "sha512-1JxbaFJj1bRKurj1uY3l4xxpU9kOUAUjcIgApj0qu1Pao5GhoIWI8iL0BeMYJ2njig1hBx0A7eKD9VGjH9wlHw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.3.tgz", + "integrity": "sha512-Bdcs4+3qlpVlx2NRn6fgX2Ue2/gGRaPeawebgclM0ERSCqDpA+owF1fdPwjJUTAJWMTuAaxjDf+hzb0/4eKvvw==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.13", + "proxy-addr": "~2.0.7", + "qs": "~6.16.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", + "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-jest": { + "version": "29.4.12", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.5", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/reference-implementations/trust-authority/package.json b/reference-implementations/trust-authority/package.json index fd5534d..c9123f1 100644 --- a/reference-implementations/trust-authority/package.json +++ b/reference-implementations/trust-authority/package.json @@ -1,7 +1,7 @@ { "name": "@blocksifr/ttp-trust-authority", "version": "0.1.0", - "description": "TTP Reference Trust Authority — aggregates behavioral receipts and issues trust tokens", + "description": "TTP Reference Trust Authority \u2014 aggregates behavioral receipts and issues trust tokens", "main": "dist/index.js", "scripts": { "build": "tsc", @@ -16,13 +16,12 @@ "@noble/ed25519": "^2.0.0", "@noble/hashes": "^1.8.0", "jose": "^5.2.0", - "uuid": "^9.0.0", + "uuid": "^11.1.0", "ajv": "^8.12.0" }, "devDependencies": { "@types/express": "^4.17.21", "@types/jest": "^29.5.14", - "@types/uuid": "^9.0.7", "@types/node": "^20.10.0", "typescript": "^5.3.0", "ts-node": "^10.9.2", diff --git a/sdk/typescript/package-lock.json b/sdk/typescript/package-lock.json new file mode 100644 index 0000000..a6de97f --- /dev/null +++ b/sdk/typescript/package-lock.json @@ -0,0 +1,4005 @@ +{ + "name": "@blocksifr/ttp-sdk", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@blocksifr/ttp-sdk", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@noble/ed25519": "^2.0.0", + "jose": "^5.2.0", + "uuid": "^11.1.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.10.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "typescript": "^5.3.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "express": "^4.x" + }, + "peerDependenciesMeta": { + "express": { + "optional": true + } + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/ed25519": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.3.0.tgz", + "integrity": "sha512-M7dvXL2B92/M7dw9+gzuydL8qn/jiqNHaoR3Q+cb1q1GHV7uwE17WCyFMG+Y+TZb5izcaXk5TdJRrDUxHXL78A==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.9.tgz", + "integrity": "sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.23", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.23.tgz", + "integrity": "sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.428", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.428.tgz", + "integrity": "sha512-1JxbaFJj1bRKurj1uY3l4xxpU9kOUAUjcIgApj0qu1Pao5GhoIWI8iL0BeMYJ2njig1hBx0A7eKD9VGjH9wlHw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "29.4.12", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.5", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/sdk/typescript/package.json b/sdk/typescript/package.json index 62caaad..a8f6314 100644 --- a/sdk/typescript/package.json +++ b/sdk/typescript/package.json @@ -19,12 +19,11 @@ "dependencies": { "@noble/ed25519": "^2.0.0", "jose": "^5.2.0", - "uuid": "^9.0.0" + "uuid": "^11.1.0" }, "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.10.0", - "@types/uuid": "^9.0.7", "typescript": "^5.3.0", "ts-jest": "^29.1.1", "jest": "^29.7.0" @@ -33,13 +32,20 @@ "express": "^4.x" }, "peerDependenciesMeta": { - "express": { "optional": true } + "express": { + "optional": true + } }, "engines": { "node": ">=18.0.0" }, "keywords": [ - "trust", "ai-agents", "behavioral-trust", "security", "ttp", "zero-trust" + "trust", + "ai-agents", + "behavioral-trust", + "security", + "ttp", + "zero-trust" ], "license": "Apache-2.0" }