{"agentPreference":["Prefer an already-installed jmpkit-publish whose version and digest match officialClient.","Otherwise download officialClient.manifestUrl and officialClient.url over HTTPS, verify size and SHA-256 before execution, and cache it with owner-only permissions.","Run the client for the directory and reuse the same installation and protected state on later publishes."],"appSuffix":"jmpkit.5304135203.app","appUrlTemplate":"https://<returned-alias>.jmpkit.5304135203.app/","baseUrl":"https://jmpkit.5304135203.com","controlHost":"jmpkit.5304135203.com","delegatedFlow":{"steps":["Agent enrolls and retains its own token.","Agent POSTs /api/agent-connections with {label, requestedScopes}; request app:create and app:manage:created for normal app publication.","Agent gives the complete approvalUrl from the response to the user. The user opens it, uses /account to prepare this browser if needed, and selects Approve or Reject.","Agent polls GET /api/agent-connections/<shortCode-or-requestId>/status with its own bearer.","After approval, agent sends the returned grantId in X-JmpKit-Grant alongside its own bearer for POST /api/apps and publication.","Owner can inspect GET /api/grants and revoke with POST /api/grants/<grantId>/revoke; the agent must stop using a revoked grant."],"summary":"An agent uses its own identity and asks a user to approve scoped access; the user never shares a bearer with the agent."},"description":"Public control plane for enrolling identities, creating apps, publishing static ZIPs, and approving delegated agent access.","discoveryVersion":"1","documentation":{"contract":"Gateway Apps contract v1 bundled with the JMPKit Gateway starter","llms":"https://jmpkit.5304135203.com/llms.txt","wellKnown":"https://jmpkit.5304135203.com/.well-known/jmpkit"},"endpoints":{"appHost":["GET /api/app10","GET /api/app10/offers","POST /api/app10/offers","DELETE /api/app10/offers/<offerId>","POST /api/app10/offers/<offerId>/claim"],"apps":["GET /api/apps","POST /api/apps","GET /api/apps/<appId>","PUT /api/apps/<appId>/alias","DELETE /api/apps/<appId>/alias"],"browserApproval":["GET /connect/<shortCode>","GET /account"],"connections":["POST /api/agent-connections","GET /api/agent-connections/<code-or-request-id>","GET /api/agent-connections/<code-or-request-id>/status","POST /api/agent-connections/<code>/approve","POST /api/agent-connections/<code>/reject"],"controlDeckCatalog":"GET /api/control-deck/catalog","createApp":"POST /api/apps","enroll":"POST /api/identity/enroll","getApp":"GET /api/apps/<appId>","grants":["GET /api/grants","GET /api/grants?role=actor","POST /api/grants/<grantId>/revoke"],"identity":["GET /api/identity/me","PATCH /api/identity/me","GET /api/identity/usage","POST /api/identity/recovery-code","GET /api/identity/location-suggestions"],"publication":["POST /api/apps/<appId>/resources/ziphost10","POST /api/apps/<appId>/publish (compatibility alias)","POST /api/apps/<appId>/resources/ziphost10/patch","POST /api/apps/<appId>/resources/ziphost10/uploads","GET|PATCH /api/apps/<appId>/resources/ziphost10/uploads/<uploadId>","POST /api/apps/<appId>/resources/ziphost10/uploads/<uploadId>/complete"],"publishZip":"POST /api/apps/<appId>/resources/ziphost10"},"implementedScope":["identity enrollment","identity profile and usage","agent approval and revocable grants","app creation and aliases","static Ziphost publication","safe public Control Deck catalog","app-host App10 inspection and ownership offers"],"mode":"gateway-apps-v1-static","name":"airnode-jmpkit-gateway","normalFlow":[{"body":"omit","name":"enroll","request":"POST /api/identity/enroll","result":"201 JSON containing token and recoveryCode once; securely retain them","step":1},{"name":"inspect_identity","request":"GET /api/identity/me with Authorization: Bearer <token>","result":"confirm the enrolled identity before creating an app","step":2},{"name":"create_app","request":"POST /api/apps with Authorization: Bearer <token> and no body","result":"201 app record; use its returned appHost and canonicalUrl, never construct a host from appId","step":3},{"name":"publish_zip","request":"POST /api/apps/<appId>/resources/ziphost10 with Authorization: Bearer <token> and Content-Type: application/zip","requirements":["ZIP must contain a root index.html","use the returned appId only in the control route","larger archives use the documented resumable upload routes"],"result":"201 with the updated app and publication metadata","step":4},{"name":"verify_live_link","request":"GET the exact returned app.canonicalUrl (or appHost plus /) without an Authorization header","result":"the published root index must be served from the canonical app host; do not use the appId as a hostname","step":5}],"officialClient":{"artifactUrl":"https://jmpkit.5304135203.com/client/jmpkit-publish.py","command":"python3 jmpkit-publish.py DIRECTORY","integrity":"sha256-4f2d079d7e31c102e342b1612edde6be33899ac0a5c12be0d22d98bfabcde73d","manifestUrl":"https://jmpkit.5304135203.com/client/manifest.json","name":"jmpkit-publish","reuse":"The protected local state file reuses the enrolled identity and app for later publishes.","runtime":"Python 3.10+ standard library only","sha256":"4f2d079d7e31c102e342b1612edde6be33899ac0a5c12be0d22d98bfabcde73d","size":17660,"url":"https://jmpkit.5304135203.com/client/jmpkit-publish.py","version":"1.0.0"},"ownershipOffers":"App-host offers are public to inspect; only the direct owner may open or revoke one, and a different enrolled entity may claim it atomically.","protocol":"JMPKit V4 Gateway Apps contract v1","publicationRules":{"complete":"A normal ZIP is a complete replacement. Optional If-Match uses one quoted active selector; If-None-Match: * requires no active publication.","limits":{"chunkBytes":8388608,"oneRequestBytes":99614720,"resumableBytes":1073741824},"patch":"Patch ZIPs require __JMPKIT_PATCH__.json and If-Match with the active selector.","verification":"The Gateway activates and verifies the Ziphost selector before committing publication metadata or catalog metadata."},"security":{"approval":"The approval URL identifies a pending request only. Approval and rejection require the browser account's own bearer; the short code alone is not authority.","bearer":"Authorization: Bearer <token>","enrollment":"POST /api/identity/enroll is public and returns one new bearer token and recovery code; retain both securely and never put them in hosted files, prompts, URLs, or logs.","grant":"X-JmpKit-Grant: <grantId> is sent with the acting agent bearer for delegated app operations.","hostAuthority":"The returned appHost/canonicalUrl is routing information, not authorization. Host and Origin headers never grant access."},"unsupportedScope":["q","Path","Origin","UWS","TURN","Web Push","Index resource APIs are not implemented by this local gateway; unsupported resource routes fail closed."],"version":"0.2"}