@nxisai/nxis 2.2.4 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- name: Deploy nxis.js to S3 and GitHub Packages
1
+ name: Deploy nxis.js to S3, GitHub Packages and npm
2
2
 
3
3
  on:
4
4
  push:
@@ -6,18 +6,29 @@ on:
6
6
  - main
7
7
  workflow_dispatch:
8
8
 
9
+ # Every job that installs needs GitHub Packages: @nxisai/webmcp resolves from
10
+ # there (package-lock.json), and the repo's .npmrc is not committed, so
11
+ # setup-node supplies the scope mapping and GITHUB_TOKEN the auth.
9
12
  jobs:
10
- build-and-deploy:
13
+ # Type-checked and built on each Node a consumer is likely to build with.
14
+ test:
11
15
  runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: read
18
+ packages: read
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ node-version: ['20', '22']
12
23
 
13
24
  steps:
14
25
  - name: Checkout code
15
26
  uses: actions/checkout@v4
16
27
 
17
- - name: Setup Node.js
28
+ - name: Setup Node.js ${{ matrix.node-version }}
18
29
  uses: actions/setup-node@v4
19
30
  with:
20
- node-version: '20'
31
+ node-version: ${{ matrix.node-version }}
21
32
  cache: 'npm'
22
33
  registry-url: 'https://npm.pkg.github.com'
23
34
  scope: '@nxisai'
@@ -27,36 +38,37 @@ jobs:
27
38
  env:
28
39
  NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
40
 
41
+ # skipLibCheck: the TypeScript this package builds with predates the
42
+ # current @types/node, whose declarations it cannot parse.
43
+ - name: Typecheck
44
+ run: npx tsc --noEmit -p . --skipLibCheck
45
+
30
46
  - name: Build project
31
47
  env:
32
48
  NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
33
- run: npx rollup --config rollup.config.js
34
-
35
- - name: Configure AWS credentials
36
- uses: aws-actions/configure-aws-credentials@v4
37
- with:
38
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
39
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
40
- aws-region: ${{ vars.AWS_REGION || secrets.AWS_REGION }}
41
-
42
- - name: Deploy to S3
43
- run: aws s3 cp build/nxis.js s3://nxis-ai-static/nxis.js
49
+ run: |
50
+ npx rollup --config rollup.config.js
51
+ npm run build:types
44
52
 
45
- publish-npm:
46
- needs: build-and-deploy
53
+ # Built and packed once, here. S3 and both registries ship these exact bytes,
54
+ # so the nxis.js a site loads from S3 is the one in the published package.
55
+ #
56
+ # Stages: test → build → deploy-s3 → publish-gpr / publish-npmjs.
57
+ build:
58
+ needs: test
47
59
  runs-on: ubuntu-latest
48
60
  permissions:
49
61
  contents: read
50
- packages: write
62
+ packages: read
51
63
 
52
64
  steps:
53
65
  - name: Checkout code
54
66
  uses: actions/checkout@v4
55
67
 
56
- - name: Setup Node.js for GitHub Packages
68
+ - name: Setup Node.js
57
69
  uses: actions/setup-node@v4
58
70
  with:
59
- node-version: '20'
71
+ node-version: '22'
60
72
  cache: 'npm'
61
73
  registry-url: 'https://npm.pkg.github.com'
62
74
  scope: '@nxisai'
@@ -66,83 +78,110 @@ jobs:
66
78
  env:
67
79
  NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
68
80
 
69
- - name: Build SSR package
81
+ - name: Build project
70
82
  env:
71
83
  NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
72
84
  run: |
73
- npx rollup --config rollup.config.js --environment NXIS_API_HOST:$NXIS_API_HOST
85
+ npx rollup --config rollup.config.js
74
86
  npm run build:types
75
87
 
76
- - name: Scope package for GitHub Packages
88
+ # Published as @nxisai/nxis; the repo's package is unscoped `nxis`.
89
+ - name: Scope the package
77
90
  run: npm pkg set name='@nxisai/nxis'
78
91
 
92
+ - name: Pack the tarball
93
+ run: npm pack
94
+
95
+ - name: Upload the tarball
96
+ uses: actions/upload-artifact@v4
97
+ with:
98
+ name: package-tarball
99
+ path: '*.tgz'
100
+ if-no-files-found: error
101
+ retention-days: 7
102
+
103
+ # Its own stage, ahead of publishing: a version reaches the registries only
104
+ # once its nxis.js is live on S3.
105
+ deploy-s3:
106
+ needs: build
107
+ runs-on: ubuntu-latest
108
+
109
+ steps:
110
+ - name: Download the tarball
111
+ uses: actions/download-artifact@v4
112
+ with:
113
+ name: package-tarball
114
+
115
+ # The browser bundle, from the tarball itself rather than a second build.
116
+ - name: Extract nxis.js
117
+ run: tar -xzf ./*.tgz package/build/nxis.js
118
+
119
+ - name: Configure AWS credentials
120
+ uses: aws-actions/configure-aws-credentials@v4
121
+ with:
122
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
123
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
124
+ aws-region: ${{ vars.AWS_REGION || secrets.AWS_REGION }}
125
+
126
+ - name: Deploy to S3
127
+ run: aws s3 cp package/build/nxis.js s3://nxis-ai-static/nxis.js
128
+
129
+ publish-gpr:
130
+ needs: deploy-s3
131
+ runs-on: ubuntu-latest
132
+ permissions:
133
+ contents: read
134
+ packages: write
135
+
136
+ steps:
137
+ - name: Setup Node.js for GitHub Packages
138
+ uses: actions/setup-node@v4
139
+ with:
140
+ node-version: '22'
141
+ registry-url: 'https://npm.pkg.github.com'
142
+ scope: '@nxisai'
143
+
144
+ - name: Download the tarball
145
+ uses: actions/download-artifact@v4
146
+ with:
147
+ name: package-tarball
148
+
149
+ # Publishing a tarball rather than a directory. npm runs no lifecycle
150
+ # scripts on one, so nothing can rebuild over the artifact that was tested.
79
151
  - name: Publish to GitHub Packages
80
- run: npm publish
152
+ run: npm publish ./*.tgz
81
153
  env:
82
154
  NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
83
155
 
156
+ # Independent of publish-gpr: a version already on GitHub Packages must not
157
+ # keep it off npm.
84
158
  publish-npmjs:
85
- needs: publish-npm
159
+ needs: deploy-s3
86
160
  runs-on: ubuntu-latest
87
161
  permissions:
88
162
  contents: read
89
- packages: read
163
+ # Required for npm Trusted Publishing (OIDC) — no npm token needed
164
+ id-token: write
90
165
 
91
166
  steps:
92
- - name: Checkout code
93
- uses: actions/checkout@v4
94
-
95
167
  - name: Setup Node.js for npm
96
168
  uses: actions/setup-node@v4
97
169
  with:
98
- node-version: '20'
99
- cache: 'npm'
100
-
101
- - name: Write .npmrc (auth both registries)
102
- run: |
103
- if [ -z "$NPM_TOKEN" ]; then
104
- echo "::error::NPM_TOKEN secret is empty"; exit 1
105
- fi
106
- echo "NPM_TOKEN length: ${#NPM_TOKEN}"
107
- # Unquoted heredoc so the shell expands the token values into the file
108
- cat > .npmrc <<EOF
109
- @nxisai:registry=https://npm.pkg.github.com
110
- //npm.pkg.github.com/:_authToken=${GH_TOKEN}
111
- //registry.npmjs.org/:_authToken=${NPM_TOKEN}
112
- always-auth=true
113
- EOF
114
- env:
115
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
116
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
117
-
118
- - name: Install dependencies
119
- run: |
120
- npm ci
121
- rm -f .npmrc
170
+ node-version: '22'
171
+ registry-url: 'https://registry.npmjs.org'
122
172
 
123
- - name: Build package
124
- env:
125
- NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
126
- run: |
127
- npx rollup --config rollup.config.js --environment NXIS_API_HOST:$NXIS_API_HOST
128
- npm run build:types
173
+ # Trusted publishing requires npm >= 11.5.1, and Node 22 still bundles
174
+ # npm 10.x. Pinned to a major rather than @latest: npm 12 raised its Node
175
+ # floor, and an unpinned @latest broke this step in nxis-webmcp.
176
+ - name: Update npm for trusted publishing
177
+ run: npm install -g npm@^11.5.1
129
178
 
130
- - name: Scope package for npm
131
- run: |
132
- npm pkg set name='@nxisai/nxis'
133
- npm pkg set publishConfig.registry='https://registry.npmjs.org'
134
-
135
- - name: Rewrite .npmrc for npmjs publish
136
- run: |
137
- # Drop the @nxisai->GitHub Packages scope mapping (only needed for install).
138
- # For a scoped package, that mapping overrides publishConfig.registry and
139
- # --registry, so it must be gone for the publish to route to npmjs.
140
- cat > .npmrc <<EOF
141
- //registry.npmjs.org/:_authToken=${NPM_TOKEN}
142
- always-auth=true
143
- EOF
144
- env:
145
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
179
+ - name: Download the tarball
180
+ uses: actions/download-artifact@v4
181
+ with:
182
+ name: package-tarball
146
183
 
184
+ # No checkout and no scope mapping, so nothing routes this scoped
185
+ # publish to GitHub Packages.
147
186
  - name: Publish to npm
148
- run: npm publish --access public --registry https://registry.npmjs.org
187
+ run: npm publish ./*.tgz --access public
package/build/nxis.js CHANGED
@@ -1 +1 @@
1
- !function(){const e={NXIS_API_HOST:"https://proxy.nxis.ai"};try{if(process)return process.env=Object.assign({},process.env),void Object.assign(process.env,e)}catch(e){}globalThis.process={env:e}}();class e extends Error{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}}var t;!function(e){e[e.OK=0]="OK",e[e.INVALID_ARGUMENT=3]="INVALID_ARGUMENT",e[e.NOT_FOUND=5]="NOT_FOUND",e[e.PERMISSION_DENIED=7]="PERMISSION_DENIED",e[e.RESOURCE_EXHAUSTED=8]="RESOURCE_EXHAUSTED",e[e.INTERNAL=13]="INTERNAL",e[e.UNAUTHENTICATED=16]="UNAUTHENTICATED"}(t||(t={})),t.OK,t.INVALID_ARGUMENT,t.NOT_FOUND,t.PERMISSION_DENIED,t.RESOURCE_EXHAUSTED,t.INTERNAL,t.UNAUTHENTICATED;class n extends Error{constructor(e,t,o){super(o),this.code=e,this.httpStatus=t,this.name="ProxyError",Object.setPrototypeOf(this,n.prototype)}get isRetryable(){return this.code===t.RESOURCE_EXHAUSTED||this.code===t.INTERNAL}get isAuthError(){return this.code===t.UNAUTHENTICATED||this.code===t.PERMISSION_DENIED}static fromResponse(e,t){return new n(t.code,e,t.message)}}function o(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function r(e,t){if(e===t)return!0;if(o(e)!==o(t))return!1;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>r(e,t[n]));if("object"===o(e)){const n=e,o=t,i=Object.keys(n);return i.length===Object.keys(o).length&&i.every(e=>r(n[e],o[e]))}return!1}function i(e,t,n="$"){if(!t||"object"!=typeof t)return[];const a=[];if(void 0===t.const||r(e,t.const)||a.push({path:n,message:`must equal const ${JSON.stringify(t.const)}`}),t.enum&&!t.enum.some(t=>r(e,t))&&a.push({path:n,message:`must be one of ${JSON.stringify(t.enum)}`}),void 0!==t.type){const r=Array.isArray(t.type)?t.type:[t.type];if(!r.some(t=>function(e,t){switch(t){case"object":return"object"===o(e);case"array":return Array.isArray(e);case"string":return"string"==typeof e;case"number":return"number"==typeof e&&Number.isFinite(e);case"integer":return"number"==typeof e&&Number.isInteger(e);case"boolean":return"boolean"==typeof e;case"null":return null===e;default:return!0}}(e,t)))return a.push({path:n,message:`expected type ${r.join(" | ")}, got ${o(e)}`}),a}if("string"==typeof e&&(void 0!==t.minLength&&e.length<t.minLength&&a.push({path:n,message:`must be at least ${t.minLength} characters`}),void 0!==t.maxLength&&e.length>t.maxLength&&a.push({path:n,message:`must be at most ${t.maxLength} characters`}),void 0!==t.pattern)){let o=null;try{o=new RegExp(t.pattern,"u")}catch{}o&&!o.test(e)&&a.push({path:n,message:`must match pattern ${t.pattern}`})}if("number"==typeof e&&(void 0!==t.minimum&&e<t.minimum&&a.push({path:n,message:`must be >= ${t.minimum}`}),void 0!==t.maximum&&e>t.maximum&&a.push({path:n,message:`must be <= ${t.maximum}`})),Array.isArray(e)&&(void 0!==t.minItems&&e.length<t.minItems&&a.push({path:n,message:`must have at least ${t.minItems} items`}),void 0!==t.maxItems&&e.length>t.maxItems&&a.push({path:n,message:`must have at most ${t.maxItems} items`}),t.items&&e.forEach((e,o)=>{a.push(...i(e,t.items,`${n}[${o}]`))})),"object"===o(e)&&!Array.isArray(e)&&null!==e){const o=e;for(const e of t.required??[])e in o||a.push({path:n,message:`missing required property "${e}"`});const r=t.properties??{};for(const[e,t]of Object.entries(r))e in o&&a.push(...i(o[e],t,`${n}.${e}`));if(!1===t.additionalProperties)for(const e of Object.keys(o))e in r||a.push({path:n,message:`unexpected property "${e}"`});else if(t.additionalProperties&&"object"==typeof t.additionalProperties)for(const e of Object.keys(o))e in r||a.push(...i(o[e],t.additionalProperties,`${n}.${e}`))}if(t.allOf)for(const o of t.allOf)a.push(...i(e,o,n));if(t.anyOf&&t.anyOf.length>0){t.anyOf.some(t=>0===i(e,t,n).length)||a.push({path:n,message:"does not match any schema in anyOf"})}if(t.oneOf&&t.oneOf.length>0){const o=t.oneOf.filter(t=>0===i(e,t,n).length).length;1!==o&&a.push({path:n,message:`must match exactly one schema in oneOf (matched ${o})`})}return a}var a,s,l,u,c,d,f=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)},p=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n};const m={type:"object"};function h(e,t){if("function"==typeof DOMException)return new DOMException(e,t);const n=new Error(e);return n.name=t,n}function v(e){if(!e||"object"!=typeof e)throw new TypeError("Tool descriptor must be an object.");if("string"!=typeof e.name||0===e.name.length)throw new TypeError("Tool descriptor requires a non-empty string 'name'.");if("string"!=typeof e.description)throw new TypeError(`Tool "${e.name}" requires a string 'description'.`);if("function"!=typeof e.execute)throw new TypeError(`Tool "${e.name}" requires an 'execute' function.`);if(void 0!==e.inputSchema&&"object"!=typeof e.inputSchema)throw new TypeError(`Tool "${e.name}": 'inputSchema' must be an object.`)}class g extends EventTarget{constructor(){super(...arguments),a.add(this),s.set(this,new Map),l.set(this,null),u.set(this,!1)}get ontoolchange(){return f(this,l,"f")}set ontoolchange(e){f(this,l,"f")&&this.removeEventListener("toolchange",f(this,l,"f")),p(this,l,"function"==typeof e?e:null,"f"),f(this,l,"f")&&this.addEventListener("toolchange",f(this,l,"f"))}registerTool(e,t={}){v(e);const{signal:n,exposedTo:o}=t;if(n?.aborted)return;f(this,a,"m",c).call(this,e.name);const r={tool:e,exposedTo:o?[...o]:void 0,pageLevel:!1};if(n){const t=()=>f(this,a,"m",c).call(this,e.name,r,!0);n.addEventListener("abort",t,{once:!0}),r.abortListener={signal:n,listener:t}}f(this,s,"f").set(e.name,r),f(this,a,"m",d).call(this)}provideContext(e={}){const t=e.tools??[];for(const e of t)v(e);if(new Set(t.map(e=>e.name)).size!==t.length)throw new TypeError("provideContext(): duplicate tool names in 'tools'.");for(const[e,t]of f(this,s,"f"))t.pageLevel&&f(this,a,"m",c).call(this,e);for(const e of t){if(f(this,s,"f").has(e.name))throw h(`provideContext(): tool "${e.name}" is already registered via registerTool().`,"InvalidStateError");f(this,s,"f").set(e.name,{tool:e,exposedTo:void 0,pageLevel:!0})}f(this,a,"m",d).call(this)}async getTools(e={}){e.fromOrigins;const t="undefined"!=typeof location?location.origin:void 0;return[...f(this,s,"f").values()].map(({tool:e})=>{const n={name:e.name,description:e.description,inputSchema:structuredClone(e.inputSchema??m)};return e.annotations&&(n.annotations=structuredClone(e.annotations)),t&&(n.origin=t),n})}async executeTool(e,t,n={}){const o=f(this,s,"f").get(e);if(!o)throw h(`No tool registered with name "${e}".`,"NotFoundError");if(n.signal?.aborted)throw h("Tool execution was aborted.","AbortError");let r;if(null==t||""===t)r={};else if("string"==typeof t)try{r=JSON.parse(t)}catch(t){throw new TypeError(`executeTool("${e}"): input is not valid JSON: ${t.message}`)}else r=t;if(null===r||"object"!=typeof r||Array.isArray(r))throw new TypeError(`executeTool("${e}"): input must be a JSON object.`);const a=i(r,o.tool.inputSchema??m);if(a.length>0){const t=a.map(e=>`${e.path}: ${e.message}`).join("; ");throw new TypeError(`executeTool("${e}"): invalid input — ${t}`)}const l=new AbortController,u=n.signal,c=()=>l.abort(u?.reason);u?.addEventListener("abort",c,{once:!0});try{const t=await o.tool.execute(r,{signal:l.signal,toolName:e});if(u?.aborted)throw h("Tool execution was aborted.","AbortError");return function(e){return null==e?{content:[]}:"string"==typeof e?{content:[{type:"text",text:e}]}:"object"==typeof e&&Array.isArray(e.content)?e:{content:[{type:"text",text:JSON.stringify(e)}]}}(t)}catch(e){if(u?.aborted||e instanceof Error&&"AbortError"===e.name)throw h("Tool execution was aborted.","AbortError");return function(e){return{isError:!0,content:[{type:"text",text:e instanceof Error?`${e.name}: ${e.message}`:String(e)}]}}(e)}finally{u?.removeEventListener("abort",c)}}unregisterTool(e){const t=f(this,a,"m",c).call(this,e);return t&&f(this,a,"m",d).call(this),t}clearContext(){if(0!==f(this,s,"f").size){for(const e of[...f(this,s,"f").keys()])f(this,a,"m",c).call(this,e);f(this,a,"m",d).call(this)}}}function y(e,t){Object.defineProperty(e,"modelContext",{value:t,writable:!1,enumerable:!0,configurable:!0})}s=new WeakMap,l=new WeakMap,u=new WeakMap,a=new WeakSet,c=function(e,t,n=!1){const o=f(this,s,"f").get(e);return!!o&&((!t||o===t)&&(o.abortListener&&o.abortListener.signal.removeEventListener("abort",o.abortListener.listener),f(this,s,"f").delete(e),n&&f(this,a,"m",d).call(this),!0))},d=function(){f(this,u,"f")||(p(this,u,!0,"f"),queueMicrotask(()=>{p(this,u,!1,"f"),this.dispatchEvent(new Event("toolchange"))}))};const w=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];const b="https://nxis.ai/ns#";function E(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function x(e,t){return E(e,t,"https://schema.org/"+t)}function A(e,t){const n=x(e,t);return"string"==typeof n?n:null}function N(e,t,n){const o=E(e,t,n);return Array.isArray(o)?o:[]}function $(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(...$(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(...$(n));return e}return[t]}return[]}function T(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!function(e){return w.includes(e)}(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=A(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=A(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=A(o,"encodingType");null!==a&&(i.encodingType=a);const s=A(o,"urlTemplate");null!==s&&(i.urlTemplate=s);const l=E(o,"nxis:targetKind",b+"targetKind");"selfPage"!==l&&"clientSide"!==l||(i["nxis:targetKind"]=l);const u=E(o,"nxis:pageUrl",b+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=E(o,"nxis:jsHandled",b+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(x(n,"target"));if(!r||!i||!a)return null;const s=N(n,"nxis:input",b+"input").map(L).filter(e=>null!==e),l=null!==(t=A(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,s);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:l,target:a,input:s.length>0?s:void 0,"nxis:extractedAt":E(n,"nxis:extractedAt",b+"extractedAt")}}function L(e){if(!e||"object"!=typeof e)return null;const t=e,n=A(t,"valueName");if(!n)return null;const o=E(t,"nxis:valueType",b+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=A(t,"description");null!==i&&(r.description=i),!0===x(t,"valueRequired")&&(r.valueRequired=!0);const a=A(t,"defaultValue");null!==a&&(r.defaultValue=a);const s=e=>{const n=x(t,e);return"number"==typeof n?n:null},l=s("valueMinLength");null!==l&&(r.valueMinLength=l);const u=s("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=s("minValue");null!==c&&(r.minValue=c);const d=s("maxValue");null!==d&&(r.maxValue=d);const f=s("stepValue");null!==f&&(r.stepValue=f);const p=A(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===x(t,"multipleValues")&&(r.multipleValues=!0),!0===x(t,"readonlyValue")&&(r.readonlyValue=!0);const m=N(t,"nxis:valueOption",b+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==A(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:A(n,"value"),name:null!==(t=A(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function O(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function S(e){const t={type:O(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function k(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:j(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function j(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function C(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function I(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=k(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),JSON.stringify(n)}const a=C(e,i),s=null!==(n=e.input)&&void 0!==n?n:[],l=[],u=[];let c=!1;for(const e of s)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=R(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):l.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&l.includes(e.valueName)){const n=e.strategy.element,r=_(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),l.splice(l.indexOf(e.valueName),1))}const d=l.length>0&&!c;let f=!1;d&&(f=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:d,submitted:f,message:M(l,u,f,r),filled:l,skipped:u};return r&&(p.stale=!0),JSON.stringify(p)}function M(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function R(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,_(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=U(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=U(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function _(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function U(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function V(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!0}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;const r=new g;"undefined"!=typeof document&&y(document,r),n&&"undefined"!=typeof navigator&&y(navigator,r)}();const r=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!r)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const i=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?i.abort():e.signal.addEventListener("abort",()=>i.abort()));const a={ids:new Set,names:new Set};P(o,r,i,a);let s=null;return n&&(s=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(H(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&P(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,r,i,a)),()=>{i.abort(),s&&(s.disconnect(),s=null)}}function P(e,t,n,o){const r=function(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=$(o);for(const e of r){const n=T(e);n&&t.push(n)}}return t}(e);let i=0;for(const e of r)if(!o.ids.has(e["@id"]))try{D(e,t,n,o),o.ids.add(e["@id"]),i++}catch(t){console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)}i>0&&console.info(`[nxis/webmcp] Registered ${i} tool(s) (${o.ids.size} total) from ${r.length} action(s).`)}function D(e,t,n,o){const r=function(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=S(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}(e),i=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);t.registerTool({name:i,description:e.description,inputSchema:r,annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:async t=>I(e,t)},{signal:n.signal}),o.names.add(i)}function H(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}function q(t){t instanceof e?console.warn(JSON.parse(t.message).message):console.error(`Unable to retrieve structured data for ${window.location.href}`)}!function(){var t,o;const r=window.__NXIS_CONFIG__,i=null!==(o=null===(t=null==r?void 0:r.webmcp)||void 0===t?void 0:t.mode)&&void 0!==o?o:"browser";if("ssr"===i)return void V();const a=process.env.NXIS_API_HOST,s=new Headers,l=new URL(`${a}/v1/nxis:inject`);l.search=function(e){var t,n;const o=new URLSearchParams;return(null===(t=e.organization_id)||void 0===t?void 0:t.value)&&o.append("organization_id",e.organization_id.value),(null===(n=e.site_id)||void 0===n?void 0:n.value)&&o.append("site_id",e.site_id.value),o.append("uri",e.uri.href),e.referrer&&o.append("referrer",e.referrer),o}({organization_id:{value:null==r?void 0:r.org_id},site_id:{value:null==r?void 0:r.site_id},uri:new URL(window.location.href),referrer:document.referrer}).toString(),(null==r?void 0:r.sub_id)&&s.set("X-NXIS-SUBSCRIPTION",r.sub_id),s.set("Content-Type","application/json"),s.set("User-Agent",navigator.userAgent),fetch(`${l}`,{headers:s}).then(t=>async function(t,o){const r=null!=o?o:"unknown";if(200===t.status){const n=await t.json();if((null==n?void 0:n.data)&&Object.keys(n.data).length>0)return n;throw new e(JSON.stringify({message:`No Nxis resource found for ${r}`}))}const i=await async function(e){try{return await e.json()}catch(e){return null}}(t);if(void 0!==(null==i?void 0:i.code)&&(null==i?void 0:i.message))throw n.fromResponse(t.status,i);switch(t.status){case 500:throw new n(13,500,"An internal server error occurred, please contact technical support.");case 502:throw new n(13,502,"An internal server error occurred, please contact technical support.");case 503:throw new n(8,503,"Service is temporarily unavailable, please try again later.");default:throw new n(13,t.status,`Unexpected response status: ${t.status}`)}}(t,window.location.href)).then(e=>{!function(e){if(e.data&&Object.keys(e.data).length>0){const t=document.createComment("Nxis.ai"),n=document.createComment("End Nxis.ai"),o=document.createElement("script");o.setAttribute("type","application/ld+json"),o.textContent=JSON.stringify(e.data),document.head.appendChild(o),o.before(t),o.after(n)}}(e),"browser"===i&&V()}).catch(q)}();
1
+ !function(){const e={NXIS_API_HOST:"https://proxy.nxis.ai"};try{if(process)return process.env=Object.assign({},process.env),void Object.assign(process.env,e)}catch(e){}globalThis.process={env:e}}();class e extends Error{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}}var t;!function(e){e[e.OK=0]="OK",e[e.INVALID_ARGUMENT=3]="INVALID_ARGUMENT",e[e.NOT_FOUND=5]="NOT_FOUND",e[e.PERMISSION_DENIED=7]="PERMISSION_DENIED",e[e.RESOURCE_EXHAUSTED=8]="RESOURCE_EXHAUSTED",e[e.INTERNAL=13]="INTERNAL",e[e.UNAUTHENTICATED=16]="UNAUTHENTICATED"}(t||(t={})),t.OK,t.INVALID_ARGUMENT,t.NOT_FOUND,t.PERMISSION_DENIED,t.RESOURCE_EXHAUSTED,t.INTERNAL,t.UNAUTHENTICATED;class n extends Error{constructor(e,t,o){super(o),this.code=e,this.httpStatus=t,this.name="ProxyError",Object.setPrototypeOf(this,n.prototype)}get isRetryable(){return this.code===t.RESOURCE_EXHAUSTED||this.code===t.INTERNAL}get isAuthError(){return this.code===t.UNAUTHENTICATED||this.code===t.PERMISSION_DENIED}static fromResponse(e,t){return new n(t.code,e,t.message)}}var o,r,i=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n},a=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};class s extends Event{constructor(e,t={}){super(e,t),o.set(this,void 0),i(this,o,`${t.toolName??""}`,"f")}get toolName(){return a(this,o,"f")}}o=new WeakMap;class l extends Event{constructor(e,t={}){super(e,t),r.set(this,void 0),i(this,r,`${t.toolName??""}`,"f")}get toolName(){return a(this,r,"f")}}r=new WeakMap;var u,c,d,f,p,m,h,v,g,w,y=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};const b=/^[A-Za-z0-9_.-]{1,128}$/;function E(e,t){return"function"==typeof DOMException?new DOMException(e,t):Object.assign(new Error(e),{name:t})}function T(e){setTimeout(e,0)}function x(e){return`${e}`}function N(e){const t=x(e);return"function"==typeof t.toWellFormed?t.toWellFormed():t.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"�")}function A(e){return"object"==typeof e&&null!==e||"function"==typeof e}function $(e){const t=JSON.stringify(e);if(void 0===t)throw new TypeError("The value cannot be serialized as JSON.");return t}function S(e,t){if(null==e)return{};if(!A(e))throw new TypeError(`The provided value is not of type '${t}'.`);return e}function j(e,t,n){const o=e[t];if(void 0===o)throw new TypeError(`Failed to read the '${t}' property from '${n}': Required member is undefined.`);return o}function C(e){const t=S(e,"ToolAnnotations"),n=e=>void 0!==t[e]&&Boolean(t[e]);return{consequentialHint:n("consequentialHint"),debugging:n("debugging"),readOnlyHint:n("readOnlyHint"),untrustedContentHint:n("untrustedContentHint")}}function O(e,t){if(void 0!==e){if("function"==typeof AbortSignal&&!(e instanceof AbortSignal))throw new TypeError(`Failed to read the 'signal' property from '${t}': The provided value is not of type 'AbortSignal'.`);return e}}function k(e,t,n){if(void 0!==e){if(!A(e)||"function"!=typeof e[Symbol.iterator])throw new TypeError(`Failed to read the '${t}' property from '${n}': The provided value cannot be converted to a sequence.`);return[...e].map(N)}}function L(e){const t="RegisteredTool",n=S(e,t);if(void 0!==n.annotations&&C(n.annotations),x(j(n,"description",t)),void 0!==n.inputSchema&&!A(n.inputSchema))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);const o=x(j(n,"name",t)),r=N(j(n,"origin",t));void 0!==n.title&&x(n.title);const i=j(n,"window",t);if(!function(e){return"undefined"==typeof window?e===globalThis:A(e)&&e.window===e}(i))throw new TypeError(`Failed to read the 'window' property from '${t}': The provided value is not of type 'Window'.`);return{name:o,origin:r,window:i}}function M(){return"undefined"!=typeof window?window:globalThis}function P(){return"undefined"!=typeof location?location.origin:"http://localhost"}function I(e){return e.map(e=>{let t;try{t=new URL(e)}catch{throw E(`"${e}" is not a valid origin.`,"SecurityError")}if(!function(e){if("null"===e.origin)return!1;if("https:"===e.protocol||"wss:"===e.protocol)return!0;const t=e.hostname;return!("localhost"!==t&&!t.endsWith(".localhost"))||/^127(?:\.\d{1,3}){3}$/.test(t)||"[::1]"===t}(t))throw E(`"${e}" is not a potentially trustworthy origin.`,"SecurityError");return t.origin})}function R(){const e=globalThis,t="undefined"!=typeof location?location.protocol:"";return!1===e.originAgentCluster&&"file:"!==t?E("This page's agent cluster is not origin-keyed.","SecurityError"):function(){if("undefined"==typeof document)return!0;const e=document,t=e.permissionsPolicy??e.featurePolicy;if(!t?.features||!t.allowsFeature)return!0;try{return!t.features().includes("tools")||t.allowsFeature("tools")}catch{return!0}}()?null:E("The 'tools' permissions policy does not allow this document to use tools.","NotAllowedError")}class U extends EventTarget{constructor(){super(...arguments),u.add(this),c.set(this,new Map),d.set(this,new Map),f.set(this,{}),p.set(this,{})}get ontoolchange(){return y(this,f,"f").toolchange??null}set ontoolchange(e){y(this,u,"m",w).call(this,"toolchange",e)}get ontoolactivated(){return y(this,f,"f").toolactivated??null}set ontoolactivated(e){y(this,u,"m",w).call(this,"toolactivated",e)}get ontoolcancel(){return y(this,f,"f").toolcancel??null}set ontoolcancel(e){y(this,u,"m",w).call(this,"toolcancel",e)}registerTool(e,t={}){let n,o,r;try{n=function(e){const t="ModelContextTool",n=S(e,t),o=void 0===n.annotations?void 0:C(n.annotations),r=x(j(n,"description",t)),i=j(n,"execute",t);if("function"!=typeof i)throw new TypeError(`Failed to read the 'execute' property from '${t}': The provided value is not a function.`);const a=n.inputSchema;if(void 0!==a&&!A(a))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);return{annotations:o,description:r,execute:i,inputSchema:a,name:x(j(n,"name",t)),title:void 0===n.title?void 0:N(n.title)}}(e);const i=S(t,"ModelContextRegisterToolOptions");r=k(i.exposedTo,"exposedTo","ModelContextRegisterToolOptions"),o=O(i.signal,"ModelContextRegisterToolOptions")}catch(e){return Promise.reject(e)}const i=R();if(i)return Promise.reject(i);const a=n.name;if(y(this,c,"f").has(a))return Promise.reject(E(`A tool named "${a}" is already registered.`,"InvalidStateError"));if(!b.test(a))return Promise.reject(E(`"${a}" is not a valid tool name: 1 to 128 ASCII letters, digits, "_", "-" or ".".`,"InvalidStateError"));if(""===n.description)return Promise.reject(E("A tool's description must not be empty.","InvalidStateError"));let s="";if(void 0!==n.inputSchema)try{s=$(n.inputSchema)}catch(e){return Promise.reject(e)}if(o?.aborted)return Promise.reject(o.reason);let l,d=[];if(r)try{d=I(r)}catch(e){return Promise.reject(e)}const f=new Promise((e,t)=>l={resolve:e,reject:t});if(o){const e=o;e.addEventListener("abort",()=>{y(this,u,"m",v).call(this,a),l.reject(e.reason)},{once:!0})}return y(this,c,"f").set(a,{name:a,title:n.title??null,description:n.description,inputSchema:s,annotations:void 0===n.annotations?null:C(n.annotations),exposedOrigins:d,tool:n}),y(this,u,"m",g).call(this),T(()=>l.resolve()),f}getTools(e={}){let t;try{t=k(S(e,"ModelContextGetToolOptions").fromOrigins,"fromOrigins","ModelContextGetToolOptions")}catch(e){return Promise.reject(e)}const n=R();if(n)return Promise.reject(n);if(t)try{I(t)}catch(e){return Promise.reject(e)}return new Promise(e=>{const t=P(),n=M(),o=[...y(this,c,"f").values()].map(e=>{const o={};return e.annotations&&(o.annotations={...e.annotations}),o.description=e.description,""!==e.inputSchema&&(o.inputSchema=JSON.parse(e.inputSchema)),o.name=e.name,o.origin=t,o.title=e.title??"",o.window=n,o});o.sort((e,t)=>e.name<t.name?-1:e.name>t.name?1:0),T(()=>e(o))})}executeTool(e,t,n={}){let o,r;try{o=L(e),r=O(S(n,"ModelContextExecuteToolOptions").signal,"ModelContextExecuteToolOptions")}catch(e){return Promise.reject(e)}const i=R();if(i)return Promise.reject(i);let a,s,l;try{a=new URL(o.origin).origin}catch{return Promise.reject(E(`"${o.origin}" is not a valid origin.`,"NotSupportedError"))}if("null"===a)return Promise.reject(E("A tool's origin must not be opaque.","NotSupportedError"));if(!A(t))return Promise.reject(new TypeError("Failed to execute 'executeTool' on 'ModelContext': The input is not an object."));try{s=$(t)}catch(e){return Promise.reject(e)}const f=new Promise((e,t)=>l={resolve:e,reject:t}),p=Symbol("tool execution");if(r){if(r.aborted)return Promise.reject(r.reason);const e=r;e.addEventListener("abort",()=>{l.reject(e.reason),T(()=>y(this,u,"m",h).call(this,p))},{once:!0})}const v=()=>T(()=>l.reject(E("The tool could not be executed.","UnknownError")));return T(()=>{if(o.window!==M()||P()!==a)return v();if(!y(this,c,"f").has(o.name))return v();const e={toolName:o.name,controller:new AbortController,started:!1,complete:(e,t)=>{y(this,d,"f").has(p)&&(y(this,d,"f").delete(p),T(()=>t?l.resolve(e):l.reject(E("The tool's execution failed.","UnknownError"))))}};y(this,d,"f").set(p,e),T(()=>y(this,u,"m",m).call(this,o.name,s,e))}),f}}function _(e,t){e in globalThis||Object.defineProperty(globalThis,e,{value:t,writable:!0,enumerable:!1,configurable:!0})}c=new WeakMap,d=new WeakMap,f=new WeakMap,p=new WeakMap,u=new WeakSet,m=function(e,t,n){const o=y(this,c,"f").get(e);if(!o)return n.complete(null,!1);let r;try{r=JSON.parse(t)}catch{return n.complete(null,!1)}if(!A(r))return n.complete(null,!1);this.dispatchEvent(new s("toolactivated",{toolName:o.name})),n.started=!0;const i={signal:n.controller.signal};let a;try{a=Promise.resolve(o.tool.execute.call(void 0,r,i))}catch(e){a=Promise.reject(e)}a.then(e=>{if(!n.started)return;let t;n.started=!1;try{t=$(e)}catch{return n.complete(null,!1)}n.complete(t,!0)},()=>{n.started&&(n.started=!1,n.complete(null,!1))})},h=function(e){const t=y(this,d,"f").get(e);t&&(y(this,d,"f").delete(e),T(()=>{t.started&&(t.started=!1,t.controller.abort(),this.dispatchEvent(new l("toolcancel",{toolName:t.toolName})))}))},v=function(e){y(this,c,"f").delete(e)&&y(this,u,"m",g).call(this)},g=function(){T(()=>this.dispatchEvent(new Event("toolchange")))},w=function(e,t){const n="function"==typeof t?t:null;if(y(this,f,"f")[e]=n,n&&!y(this,p,"f")[e]){const t=t=>{const n=y(this,f,"f")[e];n&&!1===n.call(this,t)&&t.preventDefault()};y(this,p,"f")[e]=t,this.addEventListener(e,t)}else!n&&y(this,p,"f")[e]&&(this.removeEventListener(e,y(this,p,"f")[e]),delete y(this,p,"f")[e])};const D=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];const V="https://nxis.ai/ns#";function F(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function H(e,t){return F(e,t,"https://schema.org/"+t)}function W(e,t){const n=H(e,t);return"string"==typeof n?n:null}function q(e,t,n){const o=F(e,t,n);return Array.isArray(o)?o:[]}function z(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(...z(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(...z(n));return e}return[t]}return[]}function G(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!function(e){return D.includes(e)}(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=W(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=W(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=W(o,"encodingType");null!==a&&(i.encodingType=a);const s=W(o,"urlTemplate");null!==s&&(i.urlTemplate=s);const l=F(o,"nxis:targetKind",V+"targetKind");"selfPage"!==l&&"clientSide"!==l||(i["nxis:targetKind"]=l);const u=F(o,"nxis:pageUrl",V+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=F(o,"nxis:jsHandled",V+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(H(n,"target"));if(!r||!i||!a)return null;const s=q(n,"nxis:input",V+"input").map(X).filter(e=>null!==e),l=null!==(t=W(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,s);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:l,target:a,input:s.length>0?s:void 0,"nxis:extractedAt":F(n,"nxis:extractedAt",V+"extractedAt")}}function X(e){if(!e||"object"!=typeof e)return null;const t=e,n=W(t,"valueName");if(!n)return null;const o=F(t,"nxis:valueType",V+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=W(t,"description");null!==i&&(r.description=i),!0===H(t,"valueRequired")&&(r.valueRequired=!0);const a=W(t,"defaultValue");null!==a&&(r.defaultValue=a);const s=e=>{const n=H(t,e);return"number"==typeof n?n:null},l=s("valueMinLength");null!==l&&(r.valueMinLength=l);const u=s("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=s("minValue");null!==c&&(r.minValue=c);const d=s("maxValue");null!==d&&(r.maxValue=d);const f=s("stepValue");null!==f&&(r.stepValue=f);const p=W(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===H(t,"multipleValues")&&(r.multipleValues=!0),!0===H(t,"readonlyValue")&&(r.readonlyValue=!0);const m=q(t,"nxis:valueOption",V+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==W(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:W(n,"value"),name:null!==(t=W(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function J(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function B(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=K(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}function K(e){const t={type:J(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function Q(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:Z(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function Z(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function Y(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function ee(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=Q(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),n}const a=Y(e,i),s=null!==(n=e.input)&&void 0!==n?n:[],l=[],u=[];let c=!1;for(const e of s)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=ne(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):l.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&l.includes(e.valueName)){const n=e.strategy.element,r=oe(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),l.splice(l.indexOf(e.valueName),1))}const d=l.length>0&&!c;let f=!1;d&&(f=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:d,submitted:f,message:te(l,u,f,r),filled:l,skipped:u};return r&&(p.stale=!0),p}function te(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function ne(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,oe(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=re(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=re(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function oe(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function re(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function ie(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!1}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;if(!1===globalThis.isSecureContext)return;let r;if(_("ModelContext",U),_("ToolActivatedEvent",s),_("ToolCancelEvent",l),"undefined"!=typeof document){const e=globalThis.Document;if(e&&document instanceof e){const t=new WeakMap;Object.defineProperty(e.prototype,"modelContext",{get(){if(!(this instanceof e))throw new TypeError("Illegal invocation");let n=t.get(this);return n||t.set(this,n=new U),n},enumerable:!0,configurable:!0}),Object.prototype.hasOwnProperty.call(document,"modelContext")&&delete document.modelContext}else Object.defineProperty(document,"modelContext",{value:new U,writable:!1,enumerable:!0,configurable:!0});r=document.modelContext}else r=new U;n&&"undefined"!=typeof navigator&&Object.defineProperty(navigator,"modelContext",{value:r,writable:!1,enumerable:!0,configurable:!0})}();const r=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!r)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const i=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?i.abort():e.signal.addEventListener("abort",()=>i.abort()));const a={ids:new Set,names:new Set};ae(o,r,i,a);let u=null;return n&&(u=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(se(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&ae(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,r,i,a)),()=>{i.abort(),u&&(u.disconnect(),u=null)}}async function ae(e,t,n,o){const r=function(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=z(o);for(const e of r){const n=G(e);n&&t.push(n)}}return t}(e).filter(e=>!o.ids.has(e["@id"])),i=await Promise.all(r.map(e=>async function(e,t,n,o){const r=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);o.ids.add(e["@id"]),o.names.add(r);try{const o={name:r,description:e.description||`Fill in and submit the "${e.name}" form.`,inputSchema:B(e),annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:t=>ee(e,t)};return await t.registerTool(o,{signal:n.signal}),!0}catch(t){return n.signal.aborted||(o.ids.delete(e["@id"]),o.names.delete(r),console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)),!1}}(e,t,n,o))),a=i.filter(Boolean).length;a>0&&console.info(`[nxis/webmcp] Registered ${a} tool(s) (${o.ids.size} total) from ${r.length} new action(s).`)}function se(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}const le=["nxis_handoff","nxis_intent"];function ue(e){const t=new URL(e);if(!t.search)return t;const n=t.search.slice(1).split("&").filter(e=>!le.includes(function(e){try{return decodeURIComponent(e.replace(/\+/g," "))}catch(t){return e}}(e.split("=")[0])));return t.search=n.length?`?${n.join("&")}`:"",t}function ce(t){t instanceof e?console.warn(JSON.parse(t.message).message):console.error(`Unable to retrieve structured data for ${window.location.href}`)}!function(){var t,o;const r=window.__NXIS_CONFIG__,i=null!==(o=null===(t=null==r?void 0:r.webmcp)||void 0===t?void 0:t.mode)&&void 0!==o?o:"browser";if("ssr"===i)return void ie();const a=process.env.NXIS_API_HOST,s=new Headers,l=new URL(`${a}/v1/nxis:inject`);l.search=function(e){var t,n;const o=new URLSearchParams;return(null===(t=e.organization_id)||void 0===t?void 0:t.value)&&o.append("organization_id",e.organization_id.value),(null===(n=e.site_id)||void 0===n?void 0:n.value)&&o.append("site_id",e.site_id.value),o.append("uri",e.uri.href),e.referrer&&o.append("referrer",e.referrer),o}({organization_id:{value:null==r?void 0:r.org_id},site_id:{value:null==r?void 0:r.site_id},uri:ue(window.location.href),referrer:document.referrer}).toString(),(null==r?void 0:r.sub_id)&&s.set("X-NXIS-SUBSCRIPTION",r.sub_id),s.set("Content-Type","application/json"),s.set("User-Agent",navigator.userAgent),fetch(`${l}`,{headers:s}).then(t=>async function(t,o){const r=null!=o?o:"unknown";if(200===t.status){const n=await t.json();if((null==n?void 0:n.data)&&Object.keys(n.data).length>0)return n;throw new e(JSON.stringify({message:`No Nxis resource found for ${r}`}))}const i=await async function(e){try{return await e.json()}catch(e){return null}}(t);if(void 0!==(null==i?void 0:i.code)&&(null==i?void 0:i.message))throw n.fromResponse(t.status,i);switch(t.status){case 500:throw new n(13,500,"An internal server error occurred, please contact technical support.");case 502:throw new n(13,502,"An internal server error occurred, please contact technical support.");case 503:throw new n(8,503,"Service is temporarily unavailable, please try again later.");default:throw new n(13,t.status,`Unexpected response status: ${t.status}`)}}(t,window.location.href)).then(e=>{!function(e){if(e.data&&Object.keys(e.data).length>0){const t=document.createComment("Nxis.ai"),n=document.createComment("End Nxis.ai"),o=document.createElement("script");o.setAttribute("type","application/ld+json"),o.textContent=JSON.stringify(e.data),document.head.appendChild(o),o.before(t),o.after(n)}}(e),"browser"===i&&ie()}).catch(ce)}();
@@ -11,6 +11,24 @@
11
11
  * @internal
12
12
  */
13
13
  import { NxisAction } from './contract';
14
+ /** Result of executing an action fill. */
15
+ export interface FillResult {
16
+ /** Whether the fill was meaningful (at least one field filled, no fatal errors). */
17
+ success: boolean;
18
+ /** Whether the form was submitted after filling. */
19
+ submitted: boolean;
20
+ /** Human-readable summary for agent self-correction. */
21
+ message: string;
22
+ /** Fields that were successfully filled. */
23
+ filled: string[];
24
+ /** Fields that were skipped (with actionable reasons). */
25
+ skipped: Array<{
26
+ field: string;
27
+ reason: string;
28
+ }>;
29
+ /** True when the action was extracted from a different page than the current one. */
30
+ stale?: boolean;
31
+ }
14
32
  /**
15
33
  * Execute a form fill action.
16
34
  *
@@ -19,6 +37,6 @@ import { NxisAction } from './contract';
19
37
  *
20
38
  * @param action - The NxisAction describing the form.
21
39
  * @param args - The argument values to fill, keyed by valueName.
22
- * @returns A JSON string describing the fill result.
40
+ * @returns The fill result. The WebMCP registry serializes it as JSON for the agent.
23
41
  */
24
- export declare function executeAction(action: NxisAction, args: Record<string, unknown>): Promise<string>;
42
+ export declare function executeAction(action: NxisAction, args: Record<string, unknown>): Promise<FillResult>;
@@ -9,7 +9,6 @@
9
9
  *
10
10
  * @internal
11
11
  */
12
- import './types';
13
12
  export interface RegisterOptions {
14
13
  /** Document to scan for JSON-LD blocks. Defaults to `document`. */
15
14
  doc?: Document;
@@ -1,27 +1,18 @@
1
1
  /**
2
2
  * Type declarations for the WebMCP imperative API.
3
3
  *
4
- * Augments the global `Document` and `Navigator` interfaces with
5
- * `modelContext` so TypeScript recognizes the WebMCP surface.
4
+ * The API itself — `document.modelContext`, and the global `Document`
5
+ * augmentation — is typed by `@nxisai/webmcp`, which follows the WebMCP spec
6
+ * (https://webmachinelearning.github.io/webmcp/). This file adds only what
7
+ * NxisAI tools carry beyond it.
6
8
  *
7
- * `document.modelContext` is canonical (Chrome 150+).
8
- * `navigator.modelContext` is deprecated but supported as fallback.
9
- *
10
- * @see https://developer.chrome.com/docs/ai/webmcp/imperative-api
11
9
  * @internal
12
10
  */
11
+ import type { ModelContextAPI, ModelContextTool as SpecModelContextTool, ToolAnnotations as SpecToolAnnotations } from '@nxisai/webmcp';
12
+ /** The ModelContext interface exposed on `document.modelContext`. */
13
+ export type ModelContext = ModelContextAPI;
13
14
  /** Annotations that hint to the agent how to treat a tool. */
14
- export interface ToolAnnotations {
15
- /**
16
- * If true, the tool only reads data and does not mutate the page.
17
- * Set to `false` for form-filling tools (we mutate input values).
18
- */
19
- readOnlyHint?: boolean;
20
- /**
21
- * If true, the tool's output contains untrusted content from the page.
22
- * Always `true` for NxisAI tools — we infer from content we don't control.
23
- */
24
- untrustedContentHint?: boolean;
15
+ export interface ToolAnnotations extends SpecToolAnnotations {
25
16
  /**
26
17
  * The `@id` of the Action this tool was generated from.
27
18
  *
@@ -29,53 +20,14 @@ export interface ToolAnnotations {
29
20
  * collision, so it does not identify the action on its own. A client holding
30
21
  * the same action from elsewhere — the site's MCP server, say — matches the
31
22
  * two by this.
23
+ *
24
+ * Not one of the spec's hints, so `getTools()` does not report it: a spec
25
+ * registry keeps only `readOnlyHint`, `untrustedContentHint`,
26
+ * `consequentialHint` and `debugging`.
32
27
  */
33
28
  'ai.nxis/actionId'?: string;
34
29
  }
35
30
  /** The shape passed to `modelContext.registerTool()`. */
36
- export interface ModelContextTool {
37
- /** Tool name — unique within the document. */
38
- name: string;
39
- /** Human-readable description of what the tool does. */
40
- description: string;
41
- /**
42
- * JSON Schema describing the tool's input parameters.
43
- * Passed as a plain object (type: "object" with properties).
44
- */
45
- inputSchema: Record<string, unknown>;
46
- /** Behavioral hints for the agent. */
31
+ export interface ModelContextTool extends Omit<SpecModelContextTool, 'annotations'> {
47
32
  annotations?: ToolAnnotations;
48
- /**
49
- * Called by the agent to execute the tool.
50
- * Must return a string (JSON-serialized result).
51
- */
52
- execute: (args: Record<string, unknown>) => string | Promise<string>;
53
- }
54
- /** Options for `modelContext.registerTool()`. */
55
- export interface RegisterToolOptions {
56
- /** AbortSignal to unregister the tool when aborted. */
57
- signal?: AbortSignal;
58
- }
59
- /** The ModelContext interface exposed on `document.modelContext`. */
60
- export interface ModelContext extends EventTarget {
61
- /** Register a tool for agents to discover and invoke. */
62
- registerTool(tool: ModelContextTool, options?: RegisterToolOptions): void;
63
- /** Get all currently registered tools. */
64
- getTools(): ModelContextTool[];
65
- }
66
- declare global {
67
- interface Document {
68
- /**
69
- * The WebMCP model context (canonical, Chrome 150+).
70
- * Tools are per-Document, not per-Navigator.
71
- */
72
- modelContext?: ModelContext;
73
- }
74
- interface Navigator {
75
- /**
76
- * @deprecated Use `document.modelContext` instead.
77
- * Deprecated as of Chrome 150.0.7861.0.
78
- */
79
- modelContext?: ModelContext;
80
- }
81
33
  }
package/build/webmcp.js CHANGED
@@ -1 +1 @@
1
- function e(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function t(n,o){if(n===o)return!0;if(e(n)!==e(o))return!1;if(Array.isArray(n)&&Array.isArray(o))return n.length===o.length&&n.every((e,n)=>t(e,o[n]));if("object"===e(n)){const e=n,r=o,i=Object.keys(e);return i.length===Object.keys(r).length&&i.every(n=>t(e[n],r[n]))}return!1}function n(o,r,i="$"){if(!r||"object"!=typeof r)return[];const a=[];if(void 0===r.const||t(o,r.const)||a.push({path:i,message:`must equal const ${JSON.stringify(r.const)}`}),r.enum&&!r.enum.some(e=>t(o,e))&&a.push({path:i,message:`must be one of ${JSON.stringify(r.enum)}`}),void 0!==r.type){const t=Array.isArray(r.type)?r.type:[r.type];if(!t.some(t=>function(t,n){switch(n){case"object":return"object"===e(t);case"array":return Array.isArray(t);case"string":return"string"==typeof t;case"number":return"number"==typeof t&&Number.isFinite(t);case"integer":return"number"==typeof t&&Number.isInteger(t);case"boolean":return"boolean"==typeof t;case"null":return null===t;default:return!0}}(o,t)))return a.push({path:i,message:`expected type ${t.join(" | ")}, got ${e(o)}`}),a}if("string"==typeof o&&(void 0!==r.minLength&&o.length<r.minLength&&a.push({path:i,message:`must be at least ${r.minLength} characters`}),void 0!==r.maxLength&&o.length>r.maxLength&&a.push({path:i,message:`must be at most ${r.maxLength} characters`}),void 0!==r.pattern)){let e=null;try{e=new RegExp(r.pattern,"u")}catch{}e&&!e.test(o)&&a.push({path:i,message:`must match pattern ${r.pattern}`})}if("number"==typeof o&&(void 0!==r.minimum&&o<r.minimum&&a.push({path:i,message:`must be >= ${r.minimum}`}),void 0!==r.maximum&&o>r.maximum&&a.push({path:i,message:`must be <= ${r.maximum}`})),Array.isArray(o)&&(void 0!==r.minItems&&o.length<r.minItems&&a.push({path:i,message:`must have at least ${r.minItems} items`}),void 0!==r.maxItems&&o.length>r.maxItems&&a.push({path:i,message:`must have at most ${r.maxItems} items`}),r.items&&o.forEach((e,t)=>{a.push(...n(e,r.items,`${i}[${t}]`))})),"object"===e(o)&&!Array.isArray(o)&&null!==o){const e=o;for(const t of r.required??[])t in e||a.push({path:i,message:`missing required property "${t}"`});const t=r.properties??{};for(const[o,r]of Object.entries(t))o in e&&a.push(...n(e[o],r,`${i}.${o}`));if(!1===r.additionalProperties)for(const n of Object.keys(e))n in t||a.push({path:i,message:`unexpected property "${n}"`});else if(r.additionalProperties&&"object"==typeof r.additionalProperties)for(const o of Object.keys(e))o in t||a.push(...n(e[o],r.additionalProperties,`${i}.${o}`))}if(r.allOf)for(const e of r.allOf)a.push(...n(o,e,i));if(r.anyOf&&r.anyOf.length>0){r.anyOf.some(e=>0===n(o,e,i).length)||a.push({path:i,message:"does not match any schema in anyOf"})}if(r.oneOf&&r.oneOf.length>0){const e=r.oneOf.filter(e=>0===n(o,e,i).length).length;1!==e&&a.push({path:i,message:`must match exactly one schema in oneOf (matched ${e})`})}return a}var o,r,i,a,s,l,u=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)},c=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n};const f={type:"object"};function d(e,t){if("function"==typeof DOMException)return new DOMException(e,t);const n=new Error(e);return n.name=t,n}function p(e){if(!e||"object"!=typeof e)throw new TypeError("Tool descriptor must be an object.");if("string"!=typeof e.name||0===e.name.length)throw new TypeError("Tool descriptor requires a non-empty string 'name'.");if("string"!=typeof e.description)throw new TypeError(`Tool "${e.name}" requires a string 'description'.`);if("function"!=typeof e.execute)throw new TypeError(`Tool "${e.name}" requires an 'execute' function.`);if(void 0!==e.inputSchema&&"object"!=typeof e.inputSchema)throw new TypeError(`Tool "${e.name}": 'inputSchema' must be an object.`)}class m extends EventTarget{constructor(){super(...arguments),o.add(this),r.set(this,new Map),i.set(this,null),a.set(this,!1)}get ontoolchange(){return u(this,i,"f")}set ontoolchange(e){u(this,i,"f")&&this.removeEventListener("toolchange",u(this,i,"f")),c(this,i,"function"==typeof e?e:null,"f"),u(this,i,"f")&&this.addEventListener("toolchange",u(this,i,"f"))}registerTool(e,t={}){p(e);const{signal:n,exposedTo:i}=t;if(n?.aborted)return;u(this,o,"m",s).call(this,e.name);const a={tool:e,exposedTo:i?[...i]:void 0,pageLevel:!1};if(n){const t=()=>u(this,o,"m",s).call(this,e.name,a,!0);n.addEventListener("abort",t,{once:!0}),a.abortListener={signal:n,listener:t}}u(this,r,"f").set(e.name,a),u(this,o,"m",l).call(this)}provideContext(e={}){const t=e.tools??[];for(const e of t)p(e);if(new Set(t.map(e=>e.name)).size!==t.length)throw new TypeError("provideContext(): duplicate tool names in 'tools'.");for(const[e,t]of u(this,r,"f"))t.pageLevel&&u(this,o,"m",s).call(this,e);for(const e of t){if(u(this,r,"f").has(e.name))throw d(`provideContext(): tool "${e.name}" is already registered via registerTool().`,"InvalidStateError");u(this,r,"f").set(e.name,{tool:e,exposedTo:void 0,pageLevel:!0})}u(this,o,"m",l).call(this)}async getTools(e={}){e.fromOrigins;const t="undefined"!=typeof location?location.origin:void 0;return[...u(this,r,"f").values()].map(({tool:e})=>{const n={name:e.name,description:e.description,inputSchema:structuredClone(e.inputSchema??f)};return e.annotations&&(n.annotations=structuredClone(e.annotations)),t&&(n.origin=t),n})}async executeTool(e,t,o={}){const i=u(this,r,"f").get(e);if(!i)throw d(`No tool registered with name "${e}".`,"NotFoundError");if(o.signal?.aborted)throw d("Tool execution was aborted.","AbortError");let a;if(null==t||""===t)a={};else if("string"==typeof t)try{a=JSON.parse(t)}catch(t){throw new TypeError(`executeTool("${e}"): input is not valid JSON: ${t.message}`)}else a=t;if(null===a||"object"!=typeof a||Array.isArray(a))throw new TypeError(`executeTool("${e}"): input must be a JSON object.`);const s=n(a,i.tool.inputSchema??f);if(s.length>0){const t=s.map(e=>`${e.path}: ${e.message}`).join("; ");throw new TypeError(`executeTool("${e}"): invalid input — ${t}`)}const l=new AbortController,c=o.signal,p=()=>l.abort(c?.reason);c?.addEventListener("abort",p,{once:!0});try{const t=await i.tool.execute(a,{signal:l.signal,toolName:e});if(c?.aborted)throw d("Tool execution was aborted.","AbortError");return function(e){return null==e?{content:[]}:"string"==typeof e?{content:[{type:"text",text:e}]}:"object"==typeof e&&Array.isArray(e.content)?e:{content:[{type:"text",text:JSON.stringify(e)}]}}(t)}catch(e){if(c?.aborted||e instanceof Error&&"AbortError"===e.name)throw d("Tool execution was aborted.","AbortError");return function(e){return{isError:!0,content:[{type:"text",text:e instanceof Error?`${e.name}: ${e.message}`:String(e)}]}}(e)}finally{c?.removeEventListener("abort",p)}}unregisterTool(e){const t=u(this,o,"m",s).call(this,e);return t&&u(this,o,"m",l).call(this),t}clearContext(){if(0!==u(this,r,"f").size){for(const e of[...u(this,r,"f").keys()])u(this,o,"m",s).call(this,e);u(this,o,"m",l).call(this)}}}function h(e,t){Object.defineProperty(e,"modelContext",{value:t,writable:!1,enumerable:!0,configurable:!0})}r=new WeakMap,i=new WeakMap,a=new WeakMap,o=new WeakSet,s=function(e,t,n=!1){const i=u(this,r,"f").get(e);return!!i&&((!t||i===t)&&(i.abortListener&&i.abortListener.signal.removeEventListener("abort",i.abortListener.listener),u(this,r,"f").delete(e),n&&u(this,o,"m",l).call(this),!0))},l=function(){u(this,a,"f")||(c(this,a,!0,"f"),queueMicrotask(()=>{c(this,a,!1,"f"),this.dispatchEvent(new Event("toolchange"))}))};const v=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];function g(e){return v.includes(e)}const y="https://nxis.ai/ns#";function b(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function w(e,t){return b(e,t,"https://schema.org/"+t)}function x(e,t){const n=w(e,t);return"string"==typeof n?n:null}function $(e,t,n){const o=b(e,t,n);return Array.isArray(o)?o:[]}function A(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=E(o);for(const e of r){const n=T(e);n&&t.push(n)}}return t}function E(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(...E(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(...E(n));return e}return[t]}return[]}function T(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!g(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=x(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=x(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=x(o,"encodingType");null!==a&&(i.encodingType=a);const s=x(o,"urlTemplate");null!==s&&(i.urlTemplate=s);const l=b(o,"nxis:targetKind",y+"targetKind");"selfPage"!==l&&"clientSide"!==l||(i["nxis:targetKind"]=l);const u=b(o,"nxis:pageUrl",y+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=b(o,"nxis:jsHandled",y+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(w(n,"target"));if(!r||!i||!a)return null;const s=$(n,"nxis:input",y+"input").map(L).filter(e=>null!==e),l=null!==(t=x(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,s);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:l,target:a,input:s.length>0?s:void 0,"nxis:extractedAt":b(n,"nxis:extractedAt",y+"extractedAt")}}function L(e){if(!e||"object"!=typeof e)return null;const t=e,n=x(t,"valueName");if(!n)return null;const o=b(t,"nxis:valueType",y+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=x(t,"description");null!==i&&(r.description=i),!0===w(t,"valueRequired")&&(r.valueRequired=!0);const a=x(t,"defaultValue");null!==a&&(r.defaultValue=a);const s=e=>{const n=w(t,e);return"number"==typeof n?n:null},l=s("valueMinLength");null!==l&&(r.valueMinLength=l);const u=s("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=s("minValue");null!==c&&(r.minValue=c);const f=s("maxValue");null!==f&&(r.maxValue=f);const d=s("stepValue");null!==d&&(r.stepValue=d);const p=x(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===w(t,"multipleValues")&&(r.multipleValues=!0),!0===w(t,"readonlyValue")&&(r.readonlyValue=!0);const m=$(t,"nxis:valueOption",y+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==x(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:x(n,"value"),name:null!==(t=x(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function N(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function k(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=j(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}function j(e){const t={type:N(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function S(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:O(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function O(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function C(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function M(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=S(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),JSON.stringify(n)}const a=C(e,i),s=null!==(n=e.input)&&void 0!==n?n:[],l=[],u=[];let c=!1;for(const e of s)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=q(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):l.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&l.includes(e.valueName)){const n=e.strategy.element,r=I(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),l.splice(l.indexOf(e.valueName),1))}const f=l.length>0&&!c;let d=!1;f&&(d=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:f,submitted:d,message:V(l,u,d,r),filled:l,skipped:u};return r&&(p.stale=!0),JSON.stringify(p)}function V(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function q(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,I(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=P(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=P(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function I(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function P(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function R(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!0}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;const r=new m;"undefined"!=typeof document&&h(document,r),n&&"undefined"!=typeof navigator&&h(navigator,r)}();const r=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!r)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const i=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?i.abort():e.signal.addEventListener("abort",()=>i.abort()));const a={ids:new Set,names:new Set};H(o,r,i,a);let s=null;return n&&(s=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(W(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&H(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,r,i,a)),()=>{i.abort(),s&&(s.disconnect(),s=null)}}function H(e,t,n,o){const r=A(e);let i=0;for(const e of r)if(!o.ids.has(e["@id"]))try{U(e,t,n,o),o.ids.add(e["@id"]),i++}catch(t){console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)}i>0&&console.info(`[nxis/webmcp] Registered ${i} tool(s) (${o.ids.size} total) from ${r.length} action(s).`)}function U(e,t,n,o){const r=k(e),i=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);t.registerTool({name:i,description:e.description,inputSchema:r,annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:async t=>M(e,t)},{signal:n.signal}),o.names.add(i)}function W(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}export{v as ACTION_SUBTYPES,k as buildInputSchema,g as isActionType,A as readActions,R as registerActions};
1
+ var e,t,n=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n},o=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};class r extends Event{constructor(t,o={}){super(t,o),e.set(this,void 0),n(this,e,`${o.toolName??""}`,"f")}get toolName(){return o(this,e,"f")}}e=new WeakMap;class i extends Event{constructor(e,o={}){super(e,o),t.set(this,void 0),n(this,t,`${o.toolName??""}`,"f")}get toolName(){return o(this,t,"f")}}t=new WeakMap;var a,l,s,u,c,d,f,p,m,h,v=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};const g=/^[A-Za-z0-9_.-]{1,128}$/;function w(e,t){return"function"==typeof DOMException?new DOMException(e,t):Object.assign(new Error(e),{name:t})}function y(e){setTimeout(e,0)}function b(e){return`${e}`}function x(e){const t=b(e);return"function"==typeof t.toWellFormed?t.toWellFormed():t.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"�")}function T(e){return"object"==typeof e&&null!==e||"function"==typeof e}function $(e){const t=JSON.stringify(e);if(void 0===t)throw new TypeError("The value cannot be serialized as JSON.");return t}function E(e,t){if(null==e)return{};if(!T(e))throw new TypeError(`The provided value is not of type '${t}'.`);return e}function A(e,t,n){const o=e[t];if(void 0===o)throw new TypeError(`Failed to read the '${t}' property from '${n}': Required member is undefined.`);return o}function j(e){const t=E(e,"ToolAnnotations"),n=e=>void 0!==t[e]&&Boolean(t[e]);return{consequentialHint:n("consequentialHint"),debugging:n("debugging"),readOnlyHint:n("readOnlyHint"),untrustedContentHint:n("untrustedContentHint")}}function N(e,t){if(void 0!==e){if("function"==typeof AbortSignal&&!(e instanceof AbortSignal))throw new TypeError(`Failed to read the 'signal' property from '${t}': The provided value is not of type 'AbortSignal'.`);return e}}function k(e,t,n){if(void 0!==e){if(!T(e)||"function"!=typeof e[Symbol.iterator])throw new TypeError(`Failed to read the '${t}' property from '${n}': The provided value cannot be converted to a sequence.`);return[...e].map(x)}}function S(e){const t="RegisteredTool",n=E(e,t);if(void 0!==n.annotations&&j(n.annotations),b(A(n,"description",t)),void 0!==n.inputSchema&&!T(n.inputSchema))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);const o=b(A(n,"name",t)),r=x(A(n,"origin",t));void 0!==n.title&&b(n.title);const i=A(n,"window",t);if(!function(e){return"undefined"==typeof window?e===globalThis:T(e)&&e.window===e}(i))throw new TypeError(`Failed to read the 'window' property from '${t}': The provided value is not of type 'Window'.`);return{name:o,origin:r,window:i}}function C(){return"undefined"!=typeof window?window:globalThis}function L(){return"undefined"!=typeof location?location.origin:"http://localhost"}function M(e){return e.map(e=>{let t;try{t=new URL(e)}catch{throw w(`"${e}" is not a valid origin.`,"SecurityError")}if(!function(e){if("null"===e.origin)return!1;if("https:"===e.protocol||"wss:"===e.protocol)return!0;const t=e.hostname;return!("localhost"!==t&&!t.endsWith(".localhost"))||/^127(?:\.\d{1,3}){3}$/.test(t)||"[::1]"===t}(t))throw w(`"${e}" is not a potentially trustworthy origin.`,"SecurityError");return t.origin})}function P(){const e=globalThis,t="undefined"!=typeof location?location.protocol:"";return!1===e.originAgentCluster&&"file:"!==t?w("This page's agent cluster is not origin-keyed.","SecurityError"):function(){if("undefined"==typeof document)return!0;const e=document,t=e.permissionsPolicy??e.featurePolicy;if(!t?.features||!t.allowsFeature)return!0;try{return!t.features().includes("tools")||t.allowsFeature("tools")}catch{return!0}}()?null:w("The 'tools' permissions policy does not allow this document to use tools.","NotAllowedError")}class O extends EventTarget{constructor(){super(...arguments),a.add(this),l.set(this,new Map),s.set(this,new Map),u.set(this,{}),c.set(this,{})}get ontoolchange(){return v(this,u,"f").toolchange??null}set ontoolchange(e){v(this,a,"m",h).call(this,"toolchange",e)}get ontoolactivated(){return v(this,u,"f").toolactivated??null}set ontoolactivated(e){v(this,a,"m",h).call(this,"toolactivated",e)}get ontoolcancel(){return v(this,u,"f").toolcancel??null}set ontoolcancel(e){v(this,a,"m",h).call(this,"toolcancel",e)}registerTool(e,t={}){let n,o,r;try{n=function(e){const t="ModelContextTool",n=E(e,t),o=void 0===n.annotations?void 0:j(n.annotations),r=b(A(n,"description",t)),i=A(n,"execute",t);if("function"!=typeof i)throw new TypeError(`Failed to read the 'execute' property from '${t}': The provided value is not a function.`);const a=n.inputSchema;if(void 0!==a&&!T(a))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);return{annotations:o,description:r,execute:i,inputSchema:a,name:b(A(n,"name",t)),title:void 0===n.title?void 0:x(n.title)}}(e);const i=E(t,"ModelContextRegisterToolOptions");r=k(i.exposedTo,"exposedTo","ModelContextRegisterToolOptions"),o=N(i.signal,"ModelContextRegisterToolOptions")}catch(e){return Promise.reject(e)}const i=P();if(i)return Promise.reject(i);const s=n.name;if(v(this,l,"f").has(s))return Promise.reject(w(`A tool named "${s}" is already registered.`,"InvalidStateError"));if(!g.test(s))return Promise.reject(w(`"${s}" is not a valid tool name: 1 to 128 ASCII letters, digits, "_", "-" or ".".`,"InvalidStateError"));if(""===n.description)return Promise.reject(w("A tool's description must not be empty.","InvalidStateError"));let u="";if(void 0!==n.inputSchema)try{u=$(n.inputSchema)}catch(e){return Promise.reject(e)}if(o?.aborted)return Promise.reject(o.reason);let c,d=[];if(r)try{d=M(r)}catch(e){return Promise.reject(e)}const f=new Promise((e,t)=>c={resolve:e,reject:t});if(o){const e=o;e.addEventListener("abort",()=>{v(this,a,"m",p).call(this,s),c.reject(e.reason)},{once:!0})}return v(this,l,"f").set(s,{name:s,title:n.title??null,description:n.description,inputSchema:u,annotations:void 0===n.annotations?null:j(n.annotations),exposedOrigins:d,tool:n}),v(this,a,"m",m).call(this),y(()=>c.resolve()),f}getTools(e={}){let t;try{t=k(E(e,"ModelContextGetToolOptions").fromOrigins,"fromOrigins","ModelContextGetToolOptions")}catch(e){return Promise.reject(e)}const n=P();if(n)return Promise.reject(n);if(t)try{M(t)}catch(e){return Promise.reject(e)}return new Promise(e=>{const t=L(),n=C(),o=[...v(this,l,"f").values()].map(e=>{const o={};return e.annotations&&(o.annotations={...e.annotations}),o.description=e.description,""!==e.inputSchema&&(o.inputSchema=JSON.parse(e.inputSchema)),o.name=e.name,o.origin=t,o.title=e.title??"",o.window=n,o});o.sort((e,t)=>e.name<t.name?-1:e.name>t.name?1:0),y(()=>e(o))})}executeTool(e,t,n={}){let o,r;try{o=S(e),r=N(E(n,"ModelContextExecuteToolOptions").signal,"ModelContextExecuteToolOptions")}catch(e){return Promise.reject(e)}const i=P();if(i)return Promise.reject(i);let u,c,p;try{u=new URL(o.origin).origin}catch{return Promise.reject(w(`"${o.origin}" is not a valid origin.`,"NotSupportedError"))}if("null"===u)return Promise.reject(w("A tool's origin must not be opaque.","NotSupportedError"));if(!T(t))return Promise.reject(new TypeError("Failed to execute 'executeTool' on 'ModelContext': The input is not an object."));try{c=$(t)}catch(e){return Promise.reject(e)}const m=new Promise((e,t)=>p={resolve:e,reject:t}),h=Symbol("tool execution");if(r){if(r.aborted)return Promise.reject(r.reason);const e=r;e.addEventListener("abort",()=>{p.reject(e.reason),y(()=>v(this,a,"m",f).call(this,h))},{once:!0})}const g=()=>y(()=>p.reject(w("The tool could not be executed.","UnknownError")));return y(()=>{if(o.window!==C()||L()!==u)return g();if(!v(this,l,"f").has(o.name))return g();const e={toolName:o.name,controller:new AbortController,started:!1,complete:(e,t)=>{v(this,s,"f").has(h)&&(v(this,s,"f").delete(h),y(()=>t?p.resolve(e):p.reject(w("The tool's execution failed.","UnknownError"))))}};v(this,s,"f").set(h,e),y(()=>v(this,a,"m",d).call(this,o.name,c,e))}),m}}function V(e,t){e in globalThis||Object.defineProperty(globalThis,e,{value:t,writable:!0,enumerable:!1,configurable:!0})}l=new WeakMap,s=new WeakMap,u=new WeakMap,c=new WeakMap,a=new WeakSet,d=function(e,t,n){const o=v(this,l,"f").get(e);if(!o)return n.complete(null,!1);let i;try{i=JSON.parse(t)}catch{return n.complete(null,!1)}if(!T(i))return n.complete(null,!1);this.dispatchEvent(new r("toolactivated",{toolName:o.name})),n.started=!0;const a={signal:n.controller.signal};let s;try{s=Promise.resolve(o.tool.execute.call(void 0,i,a))}catch(e){s=Promise.reject(e)}s.then(e=>{if(!n.started)return;let t;n.started=!1;try{t=$(e)}catch{return n.complete(null,!1)}n.complete(t,!0)},()=>{n.started&&(n.started=!1,n.complete(null,!1))})},f=function(e){const t=v(this,s,"f").get(e);t&&(v(this,s,"f").delete(e),y(()=>{t.started&&(t.started=!1,t.controller.abort(),this.dispatchEvent(new i("toolcancel",{toolName:t.toolName})))}))},p=function(e){v(this,l,"f").delete(e)&&v(this,a,"m",m).call(this)},m=function(){y(()=>this.dispatchEvent(new Event("toolchange")))},h=function(e,t){const n="function"==typeof t?t:null;if(v(this,u,"f")[e]=n,n&&!v(this,c,"f")[e]){const t=t=>{const n=v(this,u,"f")[e];n&&!1===n.call(this,t)&&t.preventDefault()};v(this,c,"f")[e]=t,this.addEventListener(e,t)}else!n&&v(this,c,"f")[e]&&(this.removeEventListener(e,v(this,c,"f")[e]),delete v(this,c,"f")[e])};const F=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];function R(e){return F.includes(e)}const H="https://nxis.ai/ns#";function W(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function U(e,t){return W(e,t,"https://schema.org/"+t)}function q(e,t){const n=U(e,t);return"string"==typeof n?n:null}function I(e,t,n){const o=W(e,t,n);return Array.isArray(o)?o:[]}function D(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=_(o);for(const e of r){const n=z(e);n&&t.push(n)}}return t}function _(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(..._(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(..._(n));return e}return[t]}return[]}function z(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!R(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=q(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=q(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=q(o,"encodingType");null!==a&&(i.encodingType=a);const l=q(o,"urlTemplate");null!==l&&(i.urlTemplate=l);const s=W(o,"nxis:targetKind",H+"targetKind");"selfPage"!==s&&"clientSide"!==s||(i["nxis:targetKind"]=s);const u=W(o,"nxis:pageUrl",H+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=W(o,"nxis:jsHandled",H+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(U(n,"target"));if(!r||!i||!a)return null;const l=I(n,"nxis:input",H+"input").map(B).filter(e=>null!==e),s=null!==(t=q(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,l);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:s,target:a,input:l.length>0?l:void 0,"nxis:extractedAt":W(n,"nxis:extractedAt",H+"extractedAt")}}function B(e){if(!e||"object"!=typeof e)return null;const t=e,n=q(t,"valueName");if(!n)return null;const o=W(t,"nxis:valueType",H+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=q(t,"description");null!==i&&(r.description=i),!0===U(t,"valueRequired")&&(r.valueRequired=!0);const a=q(t,"defaultValue");null!==a&&(r.defaultValue=a);const l=e=>{const n=U(t,e);return"number"==typeof n?n:null},s=l("valueMinLength");null!==s&&(r.valueMinLength=s);const u=l("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=l("minValue");null!==c&&(r.minValue=c);const d=l("maxValue");null!==d&&(r.maxValue=d);const f=l("stepValue");null!==f&&(r.stepValue=f);const p=q(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===U(t,"multipleValues")&&(r.multipleValues=!0),!0===U(t,"readonlyValue")&&(r.readonlyValue=!0);const m=I(t,"nxis:valueOption",H+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==q(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:q(n,"value"),name:null!==(t=q(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function G(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function J(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=K(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}function K(e){const t={type:G(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function Q(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:Z(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function Z(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function X(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function Y(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=Q(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),n}const a=X(e,i),l=null!==(n=e.input)&&void 0!==n?n:[],s=[],u=[];let c=!1;for(const e of l)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=te(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):s.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&s.includes(e.valueName)){const n=e.strategy.element,r=ne(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),s.splice(s.indexOf(e.valueName),1))}const d=s.length>0&&!c;let f=!1;d&&(f=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:d,submitted:f,message:ee(s,u,f,r),filled:s,skipped:u};return r&&(p.stale=!0),p}function ee(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function te(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,ne(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=oe(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=oe(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function ne(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function oe(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function re(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!1}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;if(!1===globalThis.isSecureContext)return;let a;if(V("ModelContext",O),V("ToolActivatedEvent",r),V("ToolCancelEvent",i),"undefined"!=typeof document){const e=globalThis.Document;if(e&&document instanceof e){const t=new WeakMap;Object.defineProperty(e.prototype,"modelContext",{get(){if(!(this instanceof e))throw new TypeError("Illegal invocation");let n=t.get(this);return n||t.set(this,n=new O),n},enumerable:!0,configurable:!0}),Object.prototype.hasOwnProperty.call(document,"modelContext")&&delete document.modelContext}else Object.defineProperty(document,"modelContext",{value:new O,writable:!1,enumerable:!0,configurable:!0});a=document.modelContext}else a=new O;n&&"undefined"!=typeof navigator&&Object.defineProperty(navigator,"modelContext",{value:a,writable:!1,enumerable:!0,configurable:!0})}();const a=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!a)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const l=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?l.abort():e.signal.addEventListener("abort",()=>l.abort()));const s={ids:new Set,names:new Set};ie(o,a,l,s);let u=null;return n&&(u=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(ae(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&ie(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,a,l,s)),()=>{l.abort(),u&&(u.disconnect(),u=null)}}async function ie(e,t,n,o){const r=D(e).filter(e=>!o.ids.has(e["@id"])),i=await Promise.all(r.map(e=>async function(e,t,n,o){const r=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);o.ids.add(e["@id"]),o.names.add(r);try{const o={name:r,description:e.description||`Fill in and submit the "${e.name}" form.`,inputSchema:J(e),annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:t=>Y(e,t)};return await t.registerTool(o,{signal:n.signal}),!0}catch(t){return n.signal.aborted||(o.ids.delete(e["@id"]),o.names.delete(r),console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)),!1}}(e,t,n,o))),a=i.filter(Boolean).length;a>0&&console.info(`[nxis/webmcp] Registered ${a} tool(s) (${o.ids.size} total) from ${r.length} new action(s).`)}function ae(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}export{F as ACTION_SUBTYPES,J as buildInputSchema,R as isActionType,D as readActions,re as registerActions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxisai/nxis",
3
- "version": "2.2.4",
3
+ "version": "2.3.2",
4
4
  "description": "Javascript client for Nxis AI",
5
5
  "main": "build/index.cjs.js",
6
6
  "module": "build/index.esm.js",
@@ -48,7 +48,7 @@
48
48
  "rollup-plugin-uglify": "^4.0.0"
49
49
  },
50
50
  "dependencies": {
51
- "@nxisai/webmcp": "^0.1.0",
51
+ "@nxisai/webmcp": "^0.2.0",
52
52
  "tslib": "^2.3.1",
53
53
  "typescript": "^4.4.3",
54
54
  "uuid": "^14.0.0",
@@ -56,8 +56,5 @@
56
56
  },
57
57
  "overrides": {
58
58
  "serialize-javascript": "^7.0.5"
59
- },
60
- "publishConfig": {
61
- "registry": "https://registry.npmjs.org"
62
59
  }
63
60
  }
package/src/client.ts CHANGED
@@ -53,6 +53,38 @@ function inject(response: StructuredDataResponse): void {
53
53
  *
54
54
  * @internal
55
55
  */
56
+ /** The parameters the NxisAI app adds when it hands someone to a page's agent. */
57
+ const HANDOFF_PARAMS = ["nxis_handoff", "nxis_intent"];
58
+
59
+ /**
60
+ * A page's address without the NxisAI app's handoff parameters.
61
+ *
62
+ * @param href - The address in the browser.
63
+ *
64
+ * @internal
65
+ */
66
+ function withoutHandoff(href: string): URL {
67
+ const url = new URL(href);
68
+ if (!url.search) return url;
69
+ // Pair by pair on the raw text: re-serializing the query would re-encode the
70
+ // other parameters, and the address would no longer be the registered one.
71
+ const kept = url.search
72
+ .slice(1)
73
+ .split("&")
74
+ .filter((pair) => !HANDOFF_PARAMS.includes(decodeName(pair.split("=")[0])));
75
+ url.search = kept.length ? `?${kept.join("&")}` : "";
76
+ return url;
77
+ }
78
+
79
+ /** A query parameter's name, decoded; as written when it can't be. */
80
+ function decodeName(raw: string): string {
81
+ try {
82
+ return decodeURIComponent(raw.replace(/\+/g, " "));
83
+ } catch {
84
+ return raw;
85
+ }
86
+ }
87
+
56
88
  function errorHandler(e: Error): void {
57
89
  if (e instanceof NxisWarning) {
58
90
  console.warn(JSON.parse(e.message).message);
@@ -94,7 +126,9 @@ function errorHandler(e: Error): void {
94
126
  NXIS.search = buildParams({
95
127
  organization_id: { value: config?.org_id },
96
128
  site_id: { value: config?.site_id },
97
- uri: new URL(window.location.href),
129
+ // As registered: the NxisAI app's handoff parameters name an action for the page's agent, and are never part of
130
+ // a page's address. Everything else, the fragment included, is sent as it is.
131
+ uri: withoutHandoff(window.location.href),
98
132
  referrer: document.referrer,
99
133
  }).toString();
100
134
  if (config?.sub_id) headers.set("X-NXIS-SUBSCRIPTION", config.sub_id);
@@ -20,7 +20,7 @@ import { reconcileFields, ReconciledField } from './reconcile';
20
20
  // ---------------------------------------------------------------------------
21
21
 
22
22
  /** Result of executing an action fill. */
23
- interface FillResult {
23
+ export interface FillResult {
24
24
  /** Whether the fill was meaningful (at least one field filled, no fatal errors). */
25
25
  success: boolean;
26
26
  /** Whether the form was submitted after filling. */
@@ -52,12 +52,12 @@ type FieldFillOutcome =
52
52
  *
53
53
  * @param action - The NxisAction describing the form.
54
54
  * @param args - The argument values to fill, keyed by valueName.
55
- * @returns A JSON string describing the fill result.
55
+ * @returns The fill result. The WebMCP registry serializes it as JSON for the agent.
56
56
  */
57
57
  export async function executeAction(
58
58
  action: NxisAction,
59
59
  args: Record<string, unknown>
60
- ): Promise<string> {
60
+ ): Promise<FillResult> {
61
61
  // Step 0: Staleness — the action records the page it was extracted from.
62
62
  // If the live page differs, the form may have moved or changed; surface a
63
63
  // non-fatal warning so the agent can weigh the result.
@@ -78,7 +78,7 @@ export async function executeAction(
78
78
  if (staleWarning) {
79
79
  result.stale = true;
80
80
  }
81
- return JSON.stringify(result);
81
+ return result;
82
82
  }
83
83
 
84
84
  // Step 2: Reconcile fields
@@ -165,7 +165,7 @@ export async function executeAction(
165
165
  result.stale = true;
166
166
  }
167
167
 
168
- return JSON.stringify(result);
168
+ return result;
169
169
  }
170
170
 
171
171
  // ---------------------------------------------------------------------------
@@ -10,13 +10,13 @@
10
10
  * @internal
11
11
  */
12
12
 
13
- import './types'; // Augment Document/Navigator with modelContext
14
13
  import { installWebMCPPolyfill } from '@nxisai/webmcp';
14
+ import type { ModelContextTool as SpecModelContextTool } from '@nxisai/webmcp';
15
15
  import { NxisAction } from './contract';
16
16
  import { readActions } from './parse';
17
17
  import { buildInputSchema } from './schema';
18
18
  import { executeAction } from './execute';
19
- import type { ModelContext } from './types';
19
+ import type { ModelContext, ModelContextTool } from './types';
20
20
 
21
21
  // ---------------------------------------------------------------------------
22
22
  // Public types
@@ -90,7 +90,7 @@ export function registerActions(options?: RegisterOptions): () => void {
90
90
  };
91
91
 
92
92
  // Initial registration
93
- registerFromDocument(doc, modelContext, controller, registry);
93
+ void registerFromDocument(doc, modelContext, controller, registry);
94
94
 
95
95
  // SPA re-scan via MutationObserver (always-on, opt-out via observe: false)
96
96
  let observer: MutationObserver | null = null;
@@ -134,73 +134,74 @@ function getModelContext(doc: Document): ModelContext | null {
134
134
 
135
135
  /**
136
136
  * Register tools for all Action specs found in the document.
137
+ *
138
+ * Registration is asynchronous — `registerTool` returns a promise, and every
139
+ * refusal arrives through it — so each action's `@id` and tool name are
140
+ * reserved as soon as it is attempted, and a later pass (the observer's) cannot
141
+ * try the same one while this pass waits.
137
142
  */
138
- function registerFromDocument(
143
+ async function registerFromDocument(
139
144
  doc: Document,
140
145
  modelContext: ModelContext,
141
146
  controller: AbortController,
142
147
  registry: Registry
143
- ): void {
144
- const actions = readActions(doc);
145
-
146
- let registeredThisPass = 0;
147
- for (const action of actions) {
148
- // De-dupe by @id
149
- if (registry.ids.has(action['@id'])) continue;
150
-
151
- try {
152
- registerSingleAction(action, modelContext, controller, registry);
153
- registry.ids.add(action['@id']);
154
- registeredThisPass++;
155
- } catch (err) {
156
- console.warn(
157
- `[nxis/webmcp] Failed to register tool for action "${action.name}":`,
158
- err
159
- );
160
- }
161
- }
148
+ ): Promise<void> {
149
+ const actions = readActions(doc).filter((action) => !registry.ids.has(action['@id']));
150
+ const outcomes = await Promise.all(
151
+ actions.map((action) => registerSingleAction(action, modelContext, controller, registry))
152
+ );
162
153
 
154
+ const registeredThisPass = outcomes.filter(Boolean).length;
163
155
  if (registeredThisPass > 0) {
164
156
  console.info(
165
157
  `[nxis/webmcp] Registered ${registeredThisPass} tool(s) ` +
166
- `(${registry.ids.size} total) from ${actions.length} action(s).`
158
+ `(${registry.ids.size} total) from ${actions.length} new action(s).`
167
159
  );
168
160
  }
169
161
  }
170
162
 
171
163
  /**
172
164
  * Register a single NxisAction as a WebMCP tool.
165
+ *
166
+ * @returns Whether the registry accepted it.
173
167
  */
174
- function registerSingleAction(
168
+ async function registerSingleAction(
175
169
  action: NxisAction,
176
170
  modelContext: ModelContext,
177
171
  controller: AbortController,
178
172
  registry: Registry
179
- ): void {
180
- const inputSchema = buildInputSchema(action);
173
+ ): Promise<boolean> {
181
174
  const name = uniqueToolName(sanitizeToolName(action.name), registry.names);
175
+ registry.ids.add(action['@id']);
176
+ registry.names.add(name);
182
177
 
183
- modelContext.registerTool(
184
- {
178
+ try {
179
+ const tool: ModelContextTool = {
185
180
  name,
186
- description: action.description,
187
- inputSchema,
181
+ // A registry refuses an empty description (WebMCP: InvalidStateError).
182
+ description: action.description || `Fill in and submit the "${action.name}" form.`,
183
+ inputSchema: buildInputSchema(action),
188
184
  annotations: {
189
185
  readOnlyHint: false,
190
186
  untrustedContentHint: true,
191
187
  // Which action this is, independent of the name it was given.
192
188
  'ai.nxis/actionId': action['@id'],
193
189
  },
194
- execute: async (args: Record<string, unknown>) => {
195
- return executeAction(action, args);
196
- },
197
- },
198
- { signal: controller.signal },
199
- );
200
-
201
- // Reserve the name only after a successful registration, so a failed
202
- // registerTool doesn't consume the base name and push the next action to a suffix.
203
- registry.names.add(name);
190
+ // The fill result as an object: the registry serializes it once, as JSON.
191
+ execute: (args: Record<string, unknown>) => executeAction(action, args),
192
+ };
193
+ await modelContext.registerTool(tool as SpecModelContextTool, { signal: controller.signal });
194
+ return true;
195
+ } catch (err) {
196
+ // Torn down while registering: not a failure.
197
+ if (controller.signal.aborted) return false;
198
+ // Release the reservation, so a failed registerTool doesn't consume the base name and push
199
+ // the next action to a suffix, and a later pass can try this action again.
200
+ registry.ids.delete(action['@id']);
201
+ registry.names.delete(name);
202
+ console.warn(`[nxis/webmcp] Failed to register tool for action "${action.name}":`, err);
203
+ return false;
204
+ }
204
205
  }
205
206
 
206
207
  /**
@@ -218,7 +219,7 @@ function createObserver(
218
219
  ): MutationObserver {
219
220
  const observer = new MutationObserver((mutations) => {
220
221
  if (mutationsAddJsonLd(mutations)) {
221
- registerFromDocument(doc, modelContext, controller, registry);
222
+ void registerFromDocument(doc, modelContext, controller, registry);
222
223
  }
223
224
  });
224
225
 
@@ -258,7 +259,7 @@ function isJsonLdScript(node: Node): boolean {
258
259
  /**
259
260
  * Sanitize an action name to a valid snake_case tool name.
260
261
  * Converts hyphens and spaces to underscores, strips invalid chars.
261
- * WebMCP tool names: [a-z0-9_], max 64 chars.
262
+ * Kept to [a-z0-9_] and 64 chars — within WebMCP's 1–128 of [A-Za-z0-9_.-].
262
263
  */
263
264
  function sanitizeToolName(name: string): string {
264
265
  return name
@@ -1,32 +1,25 @@
1
1
  /**
2
2
  * Type declarations for the WebMCP imperative API.
3
3
  *
4
- * Augments the global `Document` and `Navigator` interfaces with
5
- * `modelContext` so TypeScript recognizes the WebMCP surface.
4
+ * The API itself — `document.modelContext`, and the global `Document`
5
+ * augmentation — is typed by `@nxisai/webmcp`, which follows the WebMCP spec
6
+ * (https://webmachinelearning.github.io/webmcp/). This file adds only what
7
+ * NxisAI tools carry beyond it.
6
8
  *
7
- * `document.modelContext` is canonical (Chrome 150+).
8
- * `navigator.modelContext` is deprecated but supported as fallback.
9
- *
10
- * @see https://developer.chrome.com/docs/ai/webmcp/imperative-api
11
9
  * @internal
12
10
  */
13
11
 
14
- // ---------------------------------------------------------------------------
15
- // Tool registration types
16
- // ---------------------------------------------------------------------------
12
+ import type {
13
+ ModelContextAPI,
14
+ ModelContextTool as SpecModelContextTool,
15
+ ToolAnnotations as SpecToolAnnotations,
16
+ } from '@nxisai/webmcp';
17
+
18
+ /** The ModelContext interface exposed on `document.modelContext`. */
19
+ export type ModelContext = ModelContextAPI;
17
20
 
18
21
  /** Annotations that hint to the agent how to treat a tool. */
19
- export interface ToolAnnotations {
20
- /**
21
- * If true, the tool only reads data and does not mutate the page.
22
- * Set to `false` for form-filling tools (we mutate input values).
23
- */
24
- readOnlyHint?: boolean;
25
- /**
26
- * If true, the tool's output contains untrusted content from the page.
27
- * Always `true` for NxisAI tools — we infer from content we don't control.
28
- */
29
- untrustedContentHint?: boolean;
22
+ export interface ToolAnnotations extends SpecToolAnnotations {
30
23
  /**
31
24
  * The `@id` of the Action this tool was generated from.
32
25
  *
@@ -34,62 +27,15 @@ export interface ToolAnnotations {
34
27
  * collision, so it does not identify the action on its own. A client holding
35
28
  * the same action from elsewhere — the site's MCP server, say — matches the
36
29
  * two by this.
30
+ *
31
+ * Not one of the spec's hints, so `getTools()` does not report it: a spec
32
+ * registry keeps only `readOnlyHint`, `untrustedContentHint`,
33
+ * `consequentialHint` and `debugging`.
37
34
  */
38
35
  'ai.nxis/actionId'?: string;
39
36
  }
40
37
 
41
38
  /** The shape passed to `modelContext.registerTool()`. */
42
- export interface ModelContextTool {
43
- /** Tool name — unique within the document. */
44
- name: string;
45
- /** Human-readable description of what the tool does. */
46
- description: string;
47
- /**
48
- * JSON Schema describing the tool's input parameters.
49
- * Passed as a plain object (type: "object" with properties).
50
- */
51
- inputSchema: Record<string, unknown>;
52
- /** Behavioral hints for the agent. */
39
+ export interface ModelContextTool extends Omit<SpecModelContextTool, 'annotations'> {
53
40
  annotations?: ToolAnnotations;
54
- /**
55
- * Called by the agent to execute the tool.
56
- * Must return a string (JSON-serialized result).
57
- */
58
- execute: (args: Record<string, unknown>) => string | Promise<string>;
59
- }
60
-
61
- /** Options for `modelContext.registerTool()`. */
62
- export interface RegisterToolOptions {
63
- /** AbortSignal to unregister the tool when aborted. */
64
- signal?: AbortSignal;
65
- }
66
-
67
- /** The ModelContext interface exposed on `document.modelContext`. */
68
- export interface ModelContext extends EventTarget {
69
- /** Register a tool for agents to discover and invoke. */
70
- registerTool(tool: ModelContextTool, options?: RegisterToolOptions): void;
71
- /** Get all currently registered tools. */
72
- getTools(): ModelContextTool[];
73
- }
74
-
75
- // ---------------------------------------------------------------------------
76
- // Global augmentation
77
- // ---------------------------------------------------------------------------
78
-
79
- declare global {
80
- interface Document {
81
- /**
82
- * The WebMCP model context (canonical, Chrome 150+).
83
- * Tools are per-Document, not per-Navigator.
84
- */
85
- modelContext?: ModelContext;
86
- }
87
-
88
- interface Navigator {
89
- /**
90
- * @deprecated Use `document.modelContext` instead.
91
- * Deprecated as of Chrome 150.0.7861.0.
92
- */
93
- modelContext?: ModelContext;
94
- }
95
41
  }