[{"data":1,"prerenderedAt":4081},["ShallowReactive",2],{"search-de":3,"content-de-developer\u002Fplugin-contributions":4,"surround-de-\u002Fdeveloper\u002Fplugin-contributions":4073},[],{"id":5,"title":6,"body":7,"description":4066,"extension":4067,"meta":4068,"navigation":471,"path":4069,"seo":4070,"stem":4071,"__hash__":4072},"content_de\u002F3.developer\u002F42.plugin-contributions.md","Contribution-Referenz",{"type":8,"value":9,"toc":4042},"minimark",[10,24,27,53,58,63,66,237,241,248,349,379,383,393,403,1050,1088,1095,1099,1127,1144,1173,1196,1221,1233,1237,1247,1253,1297,1300,1304,1404,1437,1457,1461,1464,1470,1505,1530,1549,1570,1864,1900,1913,1949,1968,1972,1975,1981,1988,2004,2028,2573,2586,2621,2635,2639,2645,2667,2835,2842,2920,2931,2935,2941,2957,2963,2969,2975,2986,2996,3000,3006,3009,3344,3351,3370,3386,3390,3396,3412,3421,3425,3431,3443,3454,3741,3757,3760,3766,3769,3802,3812,3816,3822,3828,3835,3848,3852,3857,3938,3964,3979,3983,4018,4038],[11,12,13,14,18,19,23],"p",{},"Eine Contribution ist ein ",[15,16,17],"strong",{},"Daten-Deskriptor"," in ",[20,21,22],"code",{},"contributes.\u003Cbucket>[]",". Ihre ausführbare Hälfte liegt, sofern vorhanden, an genau einem bedingungsunabhängigen Paket-Export, den die Codegen prüft, ohne ihn auszuführen.",[11,25,26],{},"Für jeden Bucket gelten ausnahmslos zwei Regeln:",[28,29,30,46],"ul",{},[31,32,33,34,37,38,41,42,45],"li",{},"Das Manifest muss die Capability des Buckets ",[15,35,36],{},"und"," ein explizites ",[20,39,40],{},"flag"," deklarieren. Beides wird zusammen mit der Betreiber-Grant und etwaigen ",[20,43,44],{},"requiredEnvVars"," unmittelbar vor der Ausführung von Plugin-Code erneut geprüft.",[31,47,48,49,52],{},"Beigetragene Arten sind als ",[20,50,51],{},"plugin.\u003CpluginId>.\u003ClocalId>"," namensraumgebunden, sodass ein Plugin niemals eine Kern-Art oder die Art eines anderen Plugins überdecken oder mit ihr kollidieren kann.",[54,55,57],"h2",{"id":56},"bucket-übersicht","Bucket-Übersicht",[59,60,62],"h3",{"id":61},"durchgängig-verdrahtet","Durchgängig verdrahtet",[11,64,65],{},"Für diese Contributions löst heute ein produktiver Host-Pfad auf und führt sie aus.",[67,68,69,88],"table",{},[70,71,72],"thead",{},[73,74,75,79,82,85],"tr",{},[76,77,78],"th",{},"Bucket",[76,80,81],{},"Capability",[76,83,84],{},"Läuft in",[76,86,87],{},"Fehlerrichtung",[89,90,91,110,127,148,165,186,203,221],"tbody",{},[73,92,93,99,104,107],{},[94,95,96],"td",{},[20,97,98],{},"sendTransports",[94,100,101],{},[20,102,103],{},"send:transport",[94,105,106],{},"Convex-Node-Action",[94,108,109],{},"Typisierter Fehlercode; der Host besitzt die Retries",[73,111,112,117,122,124],{},[94,113,114],{},[20,115,116],{},"agentSteps",[94,118,119],{},[20,120,121],{},"agent:step",[94,123,106],{},[94,125,126],{},"Lässt den Inbox-Lebenszyklus fail-closed scheitern",[73,128,129,134,139,141],{},[94,130,131],{},[20,132,133],{},"draftStrategies",[94,135,136],{},[20,137,138],{},"draft:strategy",[94,140,106],{},[94,142,143,144,147],{},"Fällt auf die eingebaute ",[20,145,146],{},"default","-Strategie zurück",[73,149,150,155,160,162],{},[94,151,152],{},[20,153,154],{},"sendGates",[94,156,157],{},[20,158,159],{},"send:gate",[94,161,106],{},[94,163,164],{},"Leitet die Antwort in die menschliche Prüfung",[73,166,167,172,177,179],{},[94,168,169],{},[20,170,171],{},"automationSteps",[94,173,174],{},[20,175,176],{},"automation:step",[94,178,106],{},[94,180,181,182,185],{},"Schritt-Ergebnis ",[20,183,184],{},"failed",", host-eigener Retry",[73,187,188,193,198,200],{},[94,189,190],{},[20,191,192],{},"crons",[94,194,195],{},[20,196,197],{},"scheduler:cron",[94,199,106],{},[94,201,202],{},"Der Lauf wird übersprungen",[73,204,205,210,215,218],{},[94,206,207],{},[20,208,209],{},"navItems",[94,211,212],{},[20,213,214],{},"ui:navigation",[94,216,217],{},"Nuxt (nur Daten)",[94,219,220],{},"Der Eintrag wird verworfen",[73,222,223,228,233,235],{},[94,224,225],{},[20,226,227],{},"settingsPanels",[94,229,230],{},[20,231,232],{},"ui:settings",[94,234,217],{},[94,236,220],{},[59,238,240],{"id":239},"deklariert-und-katalogisiert-aber-noch-nicht-aufgerufen","Deklariert und katalogisiert — aber noch nicht aufgerufen",[11,242,243,244,247],{},"Für diese vier existieren der Manifest-Typ, die Capability-Prüfung des Validators\nund die Codegen-Metadaten. ",[15,245,246],{},"Es wird weder ein Host-Dispatch noch ein Autorisierungspfad\nausgeliefert",", ihre Deklaration hat heute also keine Laufzeitwirkung. Sie stehen hier\nund nicht bei den reservierten Namen, weil ihre Manifest-Formen verfügbar sind;\nausführbare Host-Adapter müssen jedoch zusammen mit einem konkreten Produzenten landen.",[67,249,250,264],{},[70,251,252],{},[73,253,254,256,258,261],{},[76,255,78],{},[76,257,81],{},[76,259,260],{},"Würde laufen in",[76,262,263],{},"Was heute fehlt",[89,265,266,284,310,328],{},[73,267,268,273,278,281],{},[94,269,270],{},[20,271,272],{},"automationTriggers",[94,274,275],{},[20,276,277],{},"automation:trigger",[94,279,280],{},"Convex-Mutation",[94,282,283],{},"Es existiert keine Host-Naht zum Auslösen",[73,285,286,291,296,299],{},[94,287,288],{},[20,289,290],{},"automationConditions",[94,292,293],{},[20,294,295],{},"automation:condition",[94,297,298],{},"Convex-Query",[94,300,301,302,305,306,309],{},"Es gibt keinen Plugin-Condition-Evaluator — ",[20,303,304],{},"conditions\u002Findex.ts"," wirft bei einer ",[20,307,308],{},"plugin.*","-Art",[73,311,312,317,322,325],{},[94,313,314],{},[20,315,316],{},"webhookEvents",[94,318,319],{},[20,320,321],{},"webhooks:publish",[94,323,324],{},"Nur Daten",[94,326,327],{},"Der Validator für persistierte Events ist eine geschlossene, ausschließlich Kern-Events umfassende Union, und kein Publish-Pfad autorisiert ein Plugin-Event",[73,329,330,335,340,342],{},[94,331,332],{},[20,333,334],{},"importProviders",[94,336,337],{},[20,338,339],{},"imports:provide",[94,341,106],{},[94,343,344,345,348],{},"Die Provider-Registry des Import-Walkers ist Kern-only, und ",[20,346,347],{},"integrationImports.provider"," kann keine Plugin-Art aufnehmen",[11,350,351,352,355,356,359,360,363,364,367,368,373,374,378],{},"Vier Capabilities haben keinen Contribution-Bucket: ",[20,353,354],{},"llm:invoke",", ",[20,357,358],{},"plugin-storage:read"," und ",[20,361,362],{},"plugin-storage:write"," vermittelt der Host, während ",[20,365,366],{},"worker:enqueue"," für einen nicht ausgelieferten Tier-3-Adapter reserviert ist. Die Storage-Quoten und das LLM-Budget stehen in der ",[369,370,372],"a",{"href":371},"\u002Fdeveloper\u002Fplugin-capabilities","Capability-Referenz","; das ruhende Worker-Protokoll ist unter ",[369,375,377],{"href":376},"\u002Fdeveloper\u002Fplugin-sandboxed-jobs","Gesandboxte Jobs"," dokumentiert.",[54,380,382],{"id":381},"send-transporte","Send-Transporte",[384,385,391],"pre",{"className":386,"code":388,"language":389,"meta":390},[387],"language-text","sendTransports: [{\n  id, label, module: { exportPath }, retryDelays: [\u002F* ≤ 3 bounded delays *\u002F],\n  requiredEnvVars: ['PLUGIN_ACME_TOKEN'], optionalEnvVars?,  \u002F\u002F PLUGIN_-prefixed, no \"__\"\n  credentialFields?,                                  \u002F\u002F the form, joined to those\n  supportsCustomReturnPath?, messageIdSource?, deduplicatesOnIdempotencyKey?,\n  webhook?, domainIdentity?\n}]\n","text","",[20,392,388],{"__ignoreMap":390},[11,394,395,396,398,399,402],{},"Die gespeicherte Provider-Art ist ",[20,397,51],{},". Die Codegen erzeugt einen isolate-sicheren Metadatenkatalog plus eine separate ausführbare ",[20,400,401],{},"'use node'","-Registry.",[384,404,408],{"className":405,"code":406,"language":407,"meta":390,"style":390},"language-ts shiki shiki-themes github-light github-dark-dimmed","import type {\n    PluginSendAttempt,\n    PluginSendTransportConfig,\n    PluginSendTransportModule,\n    PluginSendTransportParams,\n} from '@owlat\u002Fplugin-kit';\n\ninterface RelayExtras {\n    readonly endpoint: string;\n}\n\n\u002F** One attempt only. Owlat owns retries, health, routing, and audit. *\u002F\nexport const transport: PluginSendTransportModule\u003CRelayExtras> = {\n    parseExtras(input: unknown): RelayExtras {\n        if (typeof input !== 'object' || input === null) {\n            throw new TypeError('extras must be an object');\n        }\n        const endpoint = (input as { endpoint?: unknown }).endpoint;\n        if (typeof endpoint !== 'string' || !endpoint.startsWith('https:\u002F\u002F')) {\n            throw new TypeError('extras.endpoint must be an https URL');\n        }\n        return { endpoint };\n    },\n\n    async send(\n        params: PluginSendTransportParams,\n        extras: RelayExtras,\n        \u002F\u002F THIS INSTANCE's credentials, keyed by the name the manifest declared.\n        \u002F\u002F Never `process.env`: that reads the deployment-default instance's token\n        \u002F\u002F whichever transport id the send was addressed to.\n        config: PluginSendTransportConfig\n    ): Promise\u003CPluginSendAttempt> {\n        const response = await fetch(extras.endpoint, {\n            method: 'POST',\n            headers: {\n                'content-type': 'application\u002Fjson',\n                authorization: `Bearer ${config.env['PLUGIN_ACME_TOKEN'] ?? ''}`,\n            },\n            body: JSON.stringify({ to: params.to, from: params.from, subject: params.subject }),\n        });\n        if (response.status === 429) return { success: false, code: 'rate_limited' };\n        if (!response.ok) return { success: false, code: 'temporary_failure' };\n        return { success: true, id: response.headers.get('x-message-id') ?? '' };\n    },\n};\n","ts",[20,409,410,426,432,438,444,450,466,473,485,504,510,515,522,553,580,615,635,641,672,708,724,729,738,744,749,761,775,787,793,799,805,816,835,854,865,871,885,920,926,943,949,983,1009,1039,1044],{"__ignoreMap":390},[411,412,415,419,422],"span",{"class":413,"line":414},"line",1,[411,416,418],{"class":417},"s7YZ4","import",[411,420,421],{"class":417}," type",[411,423,425],{"class":424},"sYgZi"," {\n",[411,427,429],{"class":413,"line":428},2,[411,430,431],{"class":424},"    PluginSendAttempt,\n",[411,433,435],{"class":413,"line":434},3,[411,436,437],{"class":424},"    PluginSendTransportConfig,\n",[411,439,441],{"class":413,"line":440},4,[411,442,443],{"class":424},"    PluginSendTransportModule,\n",[411,445,447],{"class":413,"line":446},5,[411,448,449],{"class":424},"    PluginSendTransportParams,\n",[411,451,453,456,459,463],{"class":413,"line":452},6,[411,454,455],{"class":424},"} ",[411,457,458],{"class":417},"from",[411,460,462],{"class":461},"s-HuK"," '@owlat\u002Fplugin-kit'",[411,464,465],{"class":424},";\n",[411,467,469],{"class":413,"line":468},7,[411,470,472],{"emptyLinePlaceholder":471},true,"\n",[411,474,476,479,483],{"class":413,"line":475},8,[411,477,478],{"class":417},"interface",[411,480,482],{"class":481},"sOLd2"," RelayExtras",[411,484,425],{"class":424},[411,486,488,491,495,498,502],{"class":413,"line":487},9,[411,489,490],{"class":417},"    readonly",[411,492,494],{"class":493},"stnAF"," endpoint",[411,496,497],{"class":417},":",[411,499,501],{"class":500},"sviXB"," string",[411,503,465],{"class":424},[411,505,507],{"class":413,"line":506},10,[411,508,509],{"class":424},"}\n",[411,511,513],{"class":413,"line":512},11,[411,514,472],{"emptyLinePlaceholder":471},[411,516,518],{"class":413,"line":517},12,[411,519,521],{"class":520},"sDN9O","\u002F** One attempt only. Owlat owns retries, health, routing, and audit. *\u002F\n",[411,523,525,528,531,534,536,539,542,545,548,551],{"class":413,"line":524},13,[411,526,527],{"class":417},"export",[411,529,530],{"class":417}," const",[411,532,533],{"class":500}," transport",[411,535,497],{"class":417},[411,537,538],{"class":481}," PluginSendTransportModule",[411,540,541],{"class":424},"\u003C",[411,543,544],{"class":481},"RelayExtras",[411,546,547],{"class":424},"> ",[411,549,550],{"class":417},"=",[411,552,425],{"class":424},[411,554,556,560,563,566,568,571,574,576,578],{"class":413,"line":555},14,[411,557,559],{"class":558},"sPO5f","    parseExtras",[411,561,562],{"class":424},"(",[411,564,565],{"class":493},"input",[411,567,497],{"class":417},[411,569,570],{"class":500}," unknown",[411,572,573],{"class":424},")",[411,575,497],{"class":417},[411,577,482],{"class":481},[411,579,425],{"class":424},[411,581,583,586,589,592,595,598,601,604,606,609,612],{"class":413,"line":582},15,[411,584,585],{"class":417},"        if",[411,587,588],{"class":424}," (",[411,590,591],{"class":417},"typeof",[411,593,594],{"class":424}," input ",[411,596,597],{"class":417},"!==",[411,599,600],{"class":461}," 'object'",[411,602,603],{"class":417}," ||",[411,605,594],{"class":424},[411,607,608],{"class":417},"===",[411,610,611],{"class":500}," null",[411,613,614],{"class":424},") {\n",[411,616,618,621,624,627,629,632],{"class":413,"line":617},16,[411,619,620],{"class":417},"            throw",[411,622,623],{"class":417}," new",[411,625,626],{"class":558}," TypeError",[411,628,562],{"class":424},[411,630,631],{"class":461},"'extras must be an object'",[411,633,634],{"class":424},");\n",[411,636,638],{"class":413,"line":637},17,[411,639,640],{"class":424},"        }\n",[411,642,644,647,649,652,655,658,661,664,667,669],{"class":413,"line":643},18,[411,645,646],{"class":417},"        const",[411,648,494],{"class":500},[411,650,651],{"class":417}," =",[411,653,654],{"class":424}," (input ",[411,656,657],{"class":417},"as",[411,659,660],{"class":424}," { ",[411,662,663],{"class":493},"endpoint",[411,665,666],{"class":417},"?:",[411,668,570],{"class":500},[411,670,671],{"class":424}," }).endpoint;\n",[411,673,675,677,679,681,684,686,689,691,694,697,700,702,705],{"class":413,"line":674},19,[411,676,585],{"class":417},[411,678,588],{"class":424},[411,680,591],{"class":417},[411,682,683],{"class":424}," endpoint ",[411,685,597],{"class":417},[411,687,688],{"class":461}," 'string'",[411,690,603],{"class":417},[411,692,693],{"class":417}," !",[411,695,696],{"class":424},"endpoint.",[411,698,699],{"class":558},"startsWith",[411,701,562],{"class":424},[411,703,704],{"class":461},"'https:\u002F\u002F'",[411,706,707],{"class":424},")) {\n",[411,709,711,713,715,717,719,722],{"class":413,"line":710},20,[411,712,620],{"class":417},[411,714,623],{"class":417},[411,716,626],{"class":558},[411,718,562],{"class":424},[411,720,721],{"class":461},"'extras.endpoint must be an https URL'",[411,723,634],{"class":424},[411,725,727],{"class":413,"line":726},21,[411,728,640],{"class":424},[411,730,732,735],{"class":413,"line":731},22,[411,733,734],{"class":417},"        return",[411,736,737],{"class":424}," { endpoint };\n",[411,739,741],{"class":413,"line":740},23,[411,742,743],{"class":424},"    },\n",[411,745,747],{"class":413,"line":746},24,[411,748,472],{"emptyLinePlaceholder":471},[411,750,752,755,758],{"class":413,"line":751},25,[411,753,754],{"class":417},"    async",[411,756,757],{"class":558}," send",[411,759,760],{"class":424},"(\n",[411,762,764,767,769,772],{"class":413,"line":763},26,[411,765,766],{"class":493},"        params",[411,768,497],{"class":417},[411,770,771],{"class":481}," PluginSendTransportParams",[411,773,774],{"class":424},",\n",[411,776,778,781,783,785],{"class":413,"line":777},27,[411,779,780],{"class":493},"        extras",[411,782,497],{"class":417},[411,784,482],{"class":481},[411,786,774],{"class":424},[411,788,790],{"class":413,"line":789},28,[411,791,792],{"class":520},"        \u002F\u002F THIS INSTANCE's credentials, keyed by the name the manifest declared.\n",[411,794,796],{"class":413,"line":795},29,[411,797,798],{"class":520},"        \u002F\u002F Never `process.env`: that reads the deployment-default instance's token\n",[411,800,802],{"class":413,"line":801},30,[411,803,804],{"class":520},"        \u002F\u002F whichever transport id the send was addressed to.\n",[411,806,808,811,813],{"class":413,"line":807},31,[411,809,810],{"class":493},"        config",[411,812,497],{"class":417},[411,814,815],{"class":481}," PluginSendTransportConfig\n",[411,817,819,822,824,827,829,832],{"class":413,"line":818},32,[411,820,821],{"class":424},"    )",[411,823,497],{"class":417},[411,825,826],{"class":481}," Promise",[411,828,541],{"class":424},[411,830,831],{"class":481},"PluginSendAttempt",[411,833,834],{"class":424},"> {\n",[411,836,838,840,843,845,848,851],{"class":413,"line":837},33,[411,839,646],{"class":417},[411,841,842],{"class":500}," response",[411,844,651],{"class":417},[411,846,847],{"class":417}," await",[411,849,850],{"class":558}," fetch",[411,852,853],{"class":424},"(extras.endpoint, {\n",[411,855,857,860,863],{"class":413,"line":856},34,[411,858,859],{"class":424},"            method: ",[411,861,862],{"class":461},"'POST'",[411,864,774],{"class":424},[411,866,868],{"class":413,"line":867},35,[411,869,870],{"class":424},"            headers: {\n",[411,872,874,877,880,883],{"class":413,"line":873},36,[411,875,876],{"class":461},"                'content-type'",[411,878,879],{"class":424},": ",[411,881,882],{"class":461},"'application\u002Fjson'",[411,884,774],{"class":424},[411,886,888,891,894,897,900,903,906,909,912,915,918],{"class":413,"line":887},37,[411,889,890],{"class":424},"                authorization: ",[411,892,893],{"class":461},"`Bearer ${",[411,895,896],{"class":424},"config",[411,898,899],{"class":461},".",[411,901,902],{"class":424},"env",[411,904,905],{"class":461},"[",[411,907,908],{"class":461},"'PLUGIN_ACME_TOKEN'",[411,910,911],{"class":461},"] ",[411,913,914],{"class":417},"??",[411,916,917],{"class":461}," ''}`",[411,919,774],{"class":424},[411,921,923],{"class":413,"line":922},38,[411,924,925],{"class":424},"            },\n",[411,927,929,932,935,937,940],{"class":413,"line":928},39,[411,930,931],{"class":424},"            body: ",[411,933,934],{"class":500},"JSON",[411,936,899],{"class":424},[411,938,939],{"class":558},"stringify",[411,941,942],{"class":424},"({ to: params.to, from: params.from, subject: params.subject }),\n",[411,944,946],{"class":413,"line":945},40,[411,947,948],{"class":424},"        });\n",[411,950,952,954,957,959,962,965,968,971,974,977,980],{"class":413,"line":951},41,[411,953,585],{"class":417},[411,955,956],{"class":424}," (response.status ",[411,958,608],{"class":417},[411,960,961],{"class":500}," 429",[411,963,964],{"class":424},") ",[411,966,967],{"class":417},"return",[411,969,970],{"class":424}," { success: ",[411,972,973],{"class":500},"false",[411,975,976],{"class":424},", code: ",[411,978,979],{"class":461},"'rate_limited'",[411,981,982],{"class":424}," };\n",[411,984,986,988,990,993,996,998,1000,1002,1004,1007],{"class":413,"line":985},42,[411,987,585],{"class":417},[411,989,588],{"class":424},[411,991,992],{"class":417},"!",[411,994,995],{"class":424},"response.ok) ",[411,997,967],{"class":417},[411,999,970],{"class":424},[411,1001,973],{"class":500},[411,1003,976],{"class":424},[411,1005,1006],{"class":461},"'temporary_failure'",[411,1008,982],{"class":424},[411,1010,1012,1014,1016,1019,1022,1025,1027,1030,1032,1034,1037],{"class":413,"line":1011},43,[411,1013,734],{"class":417},[411,1015,970],{"class":424},[411,1017,1018],{"class":500},"true",[411,1020,1021],{"class":424},", id: response.headers.",[411,1023,1024],{"class":558},"get",[411,1026,562],{"class":424},[411,1028,1029],{"class":461},"'x-message-id'",[411,1031,964],{"class":424},[411,1033,914],{"class":417},[411,1035,1036],{"class":461}," ''",[411,1038,982],{"class":424},[411,1040,1042],{"class":413,"line":1041},44,[411,1043,743],{"class":424},[411,1045,1047],{"class":413,"line":1046},45,[411,1048,1049],{"class":424},"};\n",[11,1051,1052,1055,1056,1059,1060,1063,1064,355,1067,355,1070,355,1073,355,1076,355,1079,355,1082,355,1085,899],{},[20,1053,1054],{},"parseExtras"," ist die einzige Grenze für unbekannte Eingaben und muss den ehrlichen Extras-Typ zurückgeben oder werfen. ",[20,1057,1058],{},"send"," führt ",[15,1061,1062],{},"genau einen"," Netzwerkversuch aus. Die Fehlercodes bilden das feste Vokabular ",[20,1065,1066],{},"rate_limited",[20,1068,1069],{},"temporary_failure",[20,1071,1072],{},"ambiguous_timeout",[20,1074,1075],{},"invalid_recipient",[20,1077,1078],{},"invalid_sender",[20,1080,1081],{},"authentication_failed",[20,1083,1084],{},"content_rejected",[20,1086,1087],{},"unknown",[11,1089,1090,1091,1094],{},"Unmittelbar vor jedem Versuch prüft der Host in einer Mutation erneut die Singleton-Organisation, die Registrierung, das Flag, die Deklaration, die exakte Grant und das Vorhandensein der erforderlichen Umgebungsvariablen. Eine Verweigerung ruft nie Plugin-Code auf und wird als ",[20,1092,1093],{},"access_denied"," auditiert. Terminale Audit-Zeilen enthalten nur Systemattribution, Ergebnis und Versuchszähler — niemals Adressen, Inhalte, Provider-IDs oder rohe Fehler.",[59,1096,1098],{"id":1097},"konfiguration-und-benannte-instanzen","Konfiguration und benannte Instanzen",[11,1100,1101,1102,1104,1105,1108,1109,1111,1112,1115,1116,1119,1120,1126],{},"Deklarieren Sie die Deployment-Variablen, die Ihr Transport liest, in ",[20,1103,44],{}," \u002F ",[20,1106,1107],{},"optionalEnvVars",". Der Host löst sie auf und übergibt ",[20,1110,1058],{}," ein drittes Argument — ",[20,1113,1114],{},"{ instanceKey, env }"," —, das ",[15,1117,1118],{},"ausschließlich"," diese Variablen trägt, adressiert unter dem von Ihnen deklarierten Namen. ",[15,1121,1122,1123],{},"Lesen Sie Ihre Credentials von dort und nicht aus ",[20,1124,1125],{},"process.env",": Die Umgebung benennt die Deployment-Standardinstanz, ganz gleich an welche Transport-ID der Versand gerichtet war.",[11,1128,1129,1130,1133,1134,1137,1138,1140,1141,1143],{},"Namen müssen das Präfix ",[20,1131,1132],{},"PLUGIN_"," tragen und dürfen kein ",[20,1135,1136],{},"__"," enthalten. Das Präfix ist der Namensraum, der verhindert, dass einem Manifest ein Credential übergeben wird, das nicht dem Plugin gehört; ",[20,1139,1136],{}," ist der Instanz-Trenner, ein Basisname mit ",[20,1142,1136],{}," würde also die Variable einer anderen Instanz aliasieren.",[11,1145,1146,1147,879,1150,1153,1154,1157,1158,1161,1162,1164,1165,1168,1169,1172],{},"Erst das Deklarieren einer Konfiguration verschafft Ihrer Art zudem ",[15,1148,1149],{},"benannte Instanzen",[20,1151,1152],{},"plugin.\u003CpluginId>.\u003ClocalId>#eu",", in ",[20,1155,1156],{},"SEND_TRANSPORT_INSTANCES"," gelistet, liest ",[20,1159,1160],{},"PLUGIN_ACME_TOKEN__EU"," und kommt bei ",[20,1163,1058],{}," als ",[20,1166,1167],{},"PLUGIN_ACME_TOKEN"," mit ",[20,1170,1171],{},"instanceKey: 'eu'"," an. Eine fehlende erforderliche Variable lässt den Versuch scheitern, bevor Ihr Modul läuft. Ein Transport, der keine Konfiguration deklariert, liest weiterhin die deployment-weiten Variablen des Plugins und bekommt keine benannten Instanzen, weil ein Suffix keine davon erreicht.",[11,1174,1175,1176,1179,1180,1183,1184,1188,1189,1191,1192,1195],{},"Ihr Transport gilt als ",[15,1177,1178],{},"konfiguriert",", wenn sowohl die ",[20,1181,1182],{},"flag.requiredEnvVars"," des Plugins ",[1185,1186,1187],"em",{},"als auch"," Ihre ",[20,1190,44],{}," vollständig vorhanden sind — die Vereinigung, nicht das eine oder das andere. Ein Transport, dessen Token innerhalb eines Plugins gesetzt ist, das niemand aktiviert hat, ist nicht versandfähig, und ihn als bereit zu melden hieße, ihn auf eine Route zu setzen, die der Dispatch-Pfad anschließend verweigert. Nur Ihre eigenen Variablen tragen das Suffix ",[20,1193,1194],{},"__\u003CINSTANCEKEY>","; eine Flag-Variable ist ein deployment-weiter Schalter und wird für jede Instanz ohne Suffix gelesen.",[11,1197,1198,1201,1202,1204,1205,1207,1208,1210,1211,1213,1214,1217,1218,1220],{},[15,1199,1200],{},"Die beiden Listen dürfen sich nicht überschneiden."," Eine Variable, die sowohl in ",[20,1203,1182],{}," als auch in den ",[20,1206,44],{},"\u002F",[20,1209,1107],{}," eines Transports genannt wird, lässt die Manifest-Validierung scheitern, weil nur einer der beiden Geltungsbereiche das Suffix trägt: Eine benannte Instanz würde allein anhand von ",[20,1212,1160],{}," als konfiguriert bewertet, während die deployment-weite Variable, die das gesamte Plugin absichert, ungeprüft bliebe — und jeder Versand an diese Instanz würde vom Autorisierungspfad dann für immer verweigert. Benennen Sie beides getrennt — ",[20,1215,1216],{},"PLUGIN_ACME_ENABLED"," für das Paket, ",[20,1219,1167],{}," für den Transport.",[11,1222,1223,1225,1226,1228,1229,1232],{},[20,1224,1107],{}," darf nur zusammen mit mindestens einem ",[20,1227,44],{},"-Eintrag auftreten. Ein Transport, dessen gesamte Konfiguration optional ist, hat kein Credential, das ein Deployment setzen muss; nichts könnte also entscheiden, ob eine seiner benannten Instanzen konfiguriert ist — das Manifest wird abgelehnt, statt ihm stillschweigend ",[20,1230,1231],{},"instances_unsupported"," zu verpassen.",[59,1234,1236],{"id":1235},"das-credentials-formular","Das Credentials-Formular",[11,1238,1239,1242,1243,1246],{},[20,1240,1241],{},"credentialFields"," beschreibt, wie ein Betreiber nach den obigen Variablen GEFRAGT wird — dieselben typisierten Deskriptoren, die auch der Katalogeintrag eines Kern-Providers trägt, im bereits bekannten ",[20,1244,1245],{},"settingsSchema","-Vokabular:",[384,1248,1251],{"className":1249,"code":1250,"language":389,"meta":390},[387],"credentialFields: [\n  { kind: 'secret', key: 'token', label: 'Server token', required: true, envVar: 'PLUGIN_ACME_TOKEN' },\n  { kind: 'string', key: 'stream', label: 'Message stream', envVar: 'PLUGIN_ACME_STREAM' },\n]\n",[20,1252,1250],{"__ignoreMap":390},[11,1254,1255,1256,355,1259,355,1262,355,1265,359,1268,1271,1272,355,1275,1278,1279,1282,1283,1286,1287,1290,1291,1293,1294,1296],{},"Die Arten sind ",[20,1257,1258],{},"string",[20,1260,1261],{},"secret",[20,1263,1264],{},"number",[20,1266,1267],{},"boolean",[20,1269,1270],{},"select"," — die beiden Komposita des Katalogs (",[20,1273,1274],{},"region-select",[20,1276,1277],{},"host-port",") gehören uns, und ein Transport drückt dieselbe Konfiguration über deren Bestandteile aus. Die ",[20,1280,1281],{},"envVar"," jedes Feldes muss eine von diesem Transport deklarierte sein, passend zum ",[20,1284,1285],{},"required"," des Feldes selbst: ",[20,1288,1289],{},"required: true"," benennt ein Mitglied von ",[20,1292,44],{},", alles andere ein Mitglied von ",[20,1295,1107],{},". Diese Verknüpfung verhindert, dass ein gerendertes Formular nach einer Variable fragt, die kein Versand liest, oder genau die weglässt, die den Transport absichert.",[11,1298,1299],{},"Deskriptoren sind AUSSCHLIESSLICH BESCHREIBEND — nichts hier entscheidet, was ein Versand liest, und noch rendert keine Oberfläche das Formular eines Plugins.",[59,1301,1303],{"id":1302},"fähigkeiten","Fähigkeiten",[67,1305,1306,1319],{},[70,1307,1308],{},[73,1309,1310,1313,1316],{},[76,1311,1312],{},"Feld",[76,1314,1315],{},"Werte",[76,1317,1318],{},"Fehlen bedeutet",[89,1320,1321,1349,1376],{},[73,1322,1323,1328,1333],{},[94,1324,1325],{},[20,1326,1327],{},"supportsCustomReturnPath",[94,1329,1330],{},[20,1331,1332],{},"no",[94,1334,1335,1337,1338,359,1341,1344,1345,1348],{},[20,1336,1332],{},". Der einzige Wert, den dieses Tier hat; das Feld existiert, damit Sie ihn ausschreiben können. Die Werte ",[20,1339,1340],{},"yes",[20,1342,1343],{},"probe"," des Kern-Katalogs behaupten beide, dass Owlats eigener Bounce-Prozessor Ihre Bounces zuordnen kann — dafür braucht es einen Envelope-Sender, dessen Local Part ein VERP-Token ist, das Owlat mit einem Deployment-Secret signiert; ein Schlüssel, den kein gebündeltes Modul erhält. Eine solche Deklaration würde die Bounce-Daten Ihres Arms als vergleichbar mit unseren einstufen, während die Bounces bei Ihrem Provider landen — deshalb wird das Manifest abgelehnt. Ihr Feedback-Pfad ist der ",[20,1346,1347],{},"webhook"," weiter unten.",[73,1350,1351,1356,1364],{},[94,1352,1353],{},[20,1354,1355],{},"messageIdSource",[94,1357,1358,355,1361],{},[20,1359,1360],{},"provider",[20,1362,1363],{},"composed",[94,1365,1366,1368,1369,1371,1372,1375],{},[20,1367,1360],{},". ",[20,1370,1363],{}," sagt aus, dass Sie die von Owlat erzeugte ",[20,1373,1374],{},"Message-ID"," zurückspiegeln.",[73,1377,1378,1383,1389],{},[94,1379,1380],{},[20,1381,1382],{},"deduplicatesOnIdempotencyKey",[94,1384,1385,355,1387],{},[20,1386,1018],{},[20,1388,973],{},[94,1390,1391,1368,1393,1395,1396,1399,1400,1403],{},[20,1392,973],{},[20,1394,1018],{}," ",[15,1397,1398],{},"erfordert"," zusätzlich einen ",[20,1401,1402],{},"buildSystemMailExtras","-Export, der den Key in Ihren Request trägt; andernfalls verweigert der Host die Registrierung des Transports, denn eine Behauptung ohne die Verdrahtung macht aus einer Doppelzustellung einen „sicheren“ Retry.",[11,1405,1406,1407,1410,1411,1413,1414,1417,1418,1421,1422,1425,1426,1429,1430,359,1433,1436],{},"Zwei Katalogwerte werden aus dem ABGELEITET, was die Contribution mitbringt, statt daneben deklariert zu werden, weil ein Boolean neben der beschriebenen Sache nur im Widerspruch zu ihr stehen könnte. ",[20,1408,1409],{},"hasProviderFeedback"," ist genau dann wahr, wenn die Contribution einen ",[20,1412,1347],{}," trägt; ",[20,1415,1416],{},"domainVerification"," ist genau dann ",[20,1419,1420],{},"api",", wenn sie eine ",[20,1423,1424],{},"domainIdentity"," trägt, und andernfalls ",[20,1427,1428],{},"none",". Die übrigen Werte des Kern-Katalogs — ",[20,1431,1432],{},"acceptanceSemantics: 'accepted'",[20,1434,1435],{},"messageIdSource: 'idempotency-key'"," — stehen diesem Tier nicht zur Verfügung; jeder von ihnen schaltet Host-Maschinerie ein, die noch nicht allgemein ist, deshalb werden sie bereits beim Authoring abgelehnt, statt Ihre Sendungen falsch zu etikettieren.",[11,1438,1439,1440,1443,1444,1446,1447,1449,1450,1452,1453,1456],{},"Beide Extras-Builder sind optional, rein und synchron — kein I\u002FO, keine Uhr, keine Umgebung. ",[20,1441,1442],{},"buildDispatchExtras"," erhält die Routing-Fakten eines gesteuerten Versands (Idempotency-Key, Nachrichtentyp, Zustelldomain, IP-Pool, Warm-up-Überlauf, Engagement-Score), und ",[20,1445,1402],{}," erhält den Idempotency-Key des Aufrufers, sofern es einen gab. Was Sie zurückgeben, läuft durch Ihr eigenes ",[20,1448,1054],{},", bevor ",[20,1451,1058],{}," es sieht. Der Return-Path-Host, den Owlat für seinen eigenen Relay-Arm auflöst, gehört bewusst nicht dazu: Er ist gegen das veröffentlichte SPF ",[1185,1454,1455],{},"dieses"," Relays autorisiert, ihn aus einem anderen Transport heraus zu stempeln, würde also bei jeder so gestempelten Nachricht den SPF auf der Bounce-Domain scheitern lassen.",[59,1458,1460],{"id":1459},"feedback-webhook","Feedback-Webhook",[11,1462,1463],{},"Ein Transport, der von seinem Provider Bounces, Beschwerden, Zustellungen und Deferrals erhält, deklariert einen zweiten Modul-Export an DERSELBEN Contribution — seine Feedback-Hälfte:",[384,1465,1468],{"className":1466,"code":1467,"language":389,"meta":390},[387],"webhook: {\n  module: { exportPath },\n  signature: \u003Cone of the two host-verified schemes below>,\n  storeRawPayload?: boolean                         \u002F\u002F default false\n}\n\n\u002F\u002F The default. A contract that spells no `scheme` is this one.\nsignature: {\n  scheme?: 'hmac-timestamp-body',\n  header, algorithm, encoding, secretEnvVar,        \u002F\u002F PLUGIN_-prefixed\n  replay: { timestampHeader, toleranceSeconds }     \u002F\u002F ≤ 900\n}\n\n\u002F\u002F Svix — what Resend and many other ESP consoles sign with.\nsignature: {\n  scheme: 'svix',\n  secretEnvVar,                                     \u002F\u002F PLUGIN_-prefixed\n  toleranceSeconds                                  \u002F\u002F ≤ 900\n}\n",[20,1469,1467],{"__ignoreMap":390},[11,1471,1472,1475,1476,1104,1479,1104,1482,1485,1486,1489,1490,1493,1494,359,1497,1500,1501,1504],{},[15,1473,1474],{},"Wählen Sie das Schema, mit dem die Konsole Ihres Providers tatsächlich signiert."," Der Svix-Arm trägt nur diese zwei Felder, weil alles Übrige — die Header ",[20,1477,1478],{},"svix-id",[20,1480,1481],{},"svix-timestamp",[20,1483,1484],{},"svix-signature",", HMAC-SHA256, base64, der signierte String ",[20,1487,1488],{},"`${id}.${timestamp}.${body}`",", die Secret-Form ",[20,1491,1492],{},"whsec_"," — zum Schema gehört und einmal im Host implementiert ist; ein Manifest, das sie ausschreiben könnte, könnte dem benannten Schema nur widersprechen. Die beiden übrigen Host-Schemata, ",[20,1495,1496],{},"aws-sns",[20,1498,1499],{},"mandrill-form",", stehen diesem Tier nicht zur Verfügung: Das erste ist Host-Infrastruktur (ein Zertifikat, das Owlat abruft und cacht, gebunden an ein Topic, das dem ",[1185,1502,1503],{},"Deployment"," gehört), das zweite eine Legacy-Anbieterform, die über die öffentliche URL des Deployments selbst signiert wird.",[11,1506,1507,1508,1511,1512,1515,1516,1519,1520,1522,1523,1525,1526,1529],{},"Alle laufen auf einer Route auf: ",[20,1509,1510],{},"POST \u002Fwebhooks\u002Fplugin\u002F\u003CpluginId>",". Weil die Route nach Plugin-ID adressiert ist, darf ",[15,1513,1514],{},"höchstens ein Transport pro Plugin einen Webhook deklarieren","; ein zweiter lässt die Manifest-Validierung scheitern, ebenso ein Webhook ohne ",[20,1517,1518],{},"signature",", eine ",[20,1521,1518],{},", die ein Schema benennt, mit dem Owlat nicht verifiziert, oder eine ",[20,1524,1518],{}," des Standard-Arms ohne ",[20,1527,1528],{},"replay","-Vorkehrungen.",[11,1531,1532,1541,1542,1545,1546,1548],{},[15,1533,1534,1535,18,1538,1540],{},"Führen Sie ",[20,1536,1537],{},"secretEnvVar",[20,1539,1182],{}," auf"," — der Manifest-Validator verlangt es. Ohne das Secret kann der Host nichts verifizieren und beantwortet jede Zustellung mit ",[20,1543,1544],{},"503",", und eine Serie von Nicht-2xx-Antworten ist genau das, was einen Provider Ihren Endpunkt deaktivieren lässt; die Variable in ",[20,1547,44],{}," zu nennen, verwandelt diesen unsichtbaren Fehlschlag in ein Plugin, das ein Betreiber schlicht nicht aktivieren kann, bevor das Secret gesetzt ist.",[11,1550,1551,1554,1555,1557,1558,1561,1562,1565,1566,1569],{},[15,1552,1553],{},"Der Host verifiziert, das Plugin parst."," Owlat liest das Secret aus ",[20,1556,1537],{},", verifiziert die Bytes unter dem von Ihnen benannten Schema — derselbe Codepfad, der Owlats eigene Kern-Provider verifiziert, ein Wort zu wählen bedeutet also nie, einen Verifier zu liefern —, weist einen Zeitstempel zurück, der weiter von jetzt entfernt ist als ",[20,1559,1560],{},"toleranceSeconds",", wendet eine bereits akzeptierte Zustellung exakt kein weiteres Mal an (eine Wiederholung wird mit ",[20,1563,1564],{},"200 { success: true, duplicate: true }"," beantwortet, weil die übliche Ursache eine verlorene Bestätigung und kein Angreifer ist und ein ",[20,1567,1568],{},"4xx"," gegen Ihren Endpunkt zählen würde) und prüft Flag, Grant und Umgebung erneut, bevor die Events landen. Ein Plugin sieht das Secret nie und entscheidet nie, ob ein Request authentisch ist — der Endpunkt ist unauthentifiziert und aus dem Internet erreichbar, seine Stärke kann also keine Eigenschaft von Drittanbietercode sein.",[384,1571,1573],{"className":405,"code":1572,"language":407,"meta":390,"style":390},"import type {\n    PluginSendTransportWebhookModule,\n    PluginWebhookFeedbackEvent,\n} from '@owlat\u002Fplugin-kit';\n\n\u002F** Parse ONLY: these bytes are already verified, fresh, and not a replay. *\u002F\nexport const webhook: PluginSendTransportWebhookModule = {\n    parseEvents(rawBody: string): readonly PluginWebhookFeedbackEvent[] {\n        const batch = JSON.parse(rawBody) as { readonly records?: readonly unknown[] };\n        return (batch.records ?? []).flatMap((record) => {\n            const { type, id, at } = record as { type?: string; id?: string; at?: number };\n            if (type !== 'HardBounce' || typeof id !== 'string' || typeof at !== 'number') return [];\n            return [{ kind: 'bounced', providerMessageId: id, at, bounceType: 'hard' } as const];\n        });\n    },\n};\n",[20,1574,1575,1583,1588,1593,1603,1607,1612,1630,1657,1696,1724,1782,1826,1852,1856,1860],{"__ignoreMap":390},[411,1576,1577,1579,1581],{"class":413,"line":414},[411,1578,418],{"class":417},[411,1580,421],{"class":417},[411,1582,425],{"class":424},[411,1584,1585],{"class":413,"line":428},[411,1586,1587],{"class":424},"    PluginSendTransportWebhookModule,\n",[411,1589,1590],{"class":413,"line":434},[411,1591,1592],{"class":424},"    PluginWebhookFeedbackEvent,\n",[411,1594,1595,1597,1599,1601],{"class":413,"line":440},[411,1596,455],{"class":424},[411,1598,458],{"class":417},[411,1600,462],{"class":461},[411,1602,465],{"class":424},[411,1604,1605],{"class":413,"line":446},[411,1606,472],{"emptyLinePlaceholder":471},[411,1608,1609],{"class":413,"line":452},[411,1610,1611],{"class":520},"\u002F** Parse ONLY: these bytes are already verified, fresh, and not a replay. *\u002F\n",[411,1613,1614,1616,1618,1621,1623,1626,1628],{"class":413,"line":468},[411,1615,527],{"class":417},[411,1617,530],{"class":417},[411,1619,1620],{"class":500}," webhook",[411,1622,497],{"class":417},[411,1624,1625],{"class":481}," PluginSendTransportWebhookModule",[411,1627,651],{"class":417},[411,1629,425],{"class":424},[411,1631,1632,1635,1637,1640,1642,1644,1646,1648,1651,1654],{"class":413,"line":475},[411,1633,1634],{"class":558},"    parseEvents",[411,1636,562],{"class":424},[411,1638,1639],{"class":493},"rawBody",[411,1641,497],{"class":417},[411,1643,501],{"class":500},[411,1645,573],{"class":424},[411,1647,497],{"class":417},[411,1649,1650],{"class":417}," readonly",[411,1652,1653],{"class":481}," PluginWebhookFeedbackEvent",[411,1655,1656],{"class":424},"[] {\n",[411,1658,1659,1661,1664,1666,1669,1671,1674,1677,1679,1681,1684,1687,1689,1691,1693],{"class":413,"line":487},[411,1660,646],{"class":417},[411,1662,1663],{"class":500}," batch",[411,1665,651],{"class":417},[411,1667,1668],{"class":500}," JSON",[411,1670,899],{"class":424},[411,1672,1673],{"class":558},"parse",[411,1675,1676],{"class":424},"(rawBody) ",[411,1678,657],{"class":417},[411,1680,660],{"class":424},[411,1682,1683],{"class":417},"readonly",[411,1685,1686],{"class":493}," records",[411,1688,666],{"class":417},[411,1690,1650],{"class":417},[411,1692,570],{"class":500},[411,1694,1695],{"class":424},"[] };\n",[411,1697,1698,1700,1703,1705,1708,1711,1714,1717,1719,1722],{"class":413,"line":506},[411,1699,734],{"class":417},[411,1701,1702],{"class":424}," (batch.records ",[411,1704,914],{"class":417},[411,1706,1707],{"class":424}," []).",[411,1709,1710],{"class":558},"flatMap",[411,1712,1713],{"class":424},"((",[411,1715,1716],{"class":493},"record",[411,1718,964],{"class":424},[411,1720,1721],{"class":417},"=>",[411,1723,425],{"class":424},[411,1725,1726,1729,1731,1734,1736,1739,1741,1744,1747,1749,1752,1754,1756,1758,1760,1762,1765,1767,1769,1771,1773,1775,1777,1780],{"class":413,"line":512},[411,1727,1728],{"class":417},"            const",[411,1730,660],{"class":424},[411,1732,1733],{"class":500},"type",[411,1735,355],{"class":424},[411,1737,1738],{"class":500},"id",[411,1740,355],{"class":424},[411,1742,1743],{"class":500},"at",[411,1745,1746],{"class":424}," } ",[411,1748,550],{"class":417},[411,1750,1751],{"class":424}," record ",[411,1753,657],{"class":417},[411,1755,660],{"class":424},[411,1757,1733],{"class":493},[411,1759,666],{"class":417},[411,1761,501],{"class":500},[411,1763,1764],{"class":424},"; ",[411,1766,1738],{"class":493},[411,1768,666],{"class":417},[411,1770,501],{"class":500},[411,1772,1764],{"class":424},[411,1774,1743],{"class":493},[411,1776,666],{"class":417},[411,1778,1779],{"class":500}," number",[411,1781,982],{"class":424},[411,1783,1784,1787,1790,1792,1795,1797,1800,1803,1805,1807,1809,1811,1814,1816,1819,1821,1823],{"class":413,"line":517},[411,1785,1786],{"class":417},"            if",[411,1788,1789],{"class":424}," (type ",[411,1791,597],{"class":417},[411,1793,1794],{"class":461}," 'HardBounce'",[411,1796,603],{"class":417},[411,1798,1799],{"class":417}," typeof",[411,1801,1802],{"class":424}," id ",[411,1804,597],{"class":417},[411,1806,688],{"class":461},[411,1808,603],{"class":417},[411,1810,1799],{"class":417},[411,1812,1813],{"class":424}," at ",[411,1815,597],{"class":417},[411,1817,1818],{"class":461}," 'number'",[411,1820,964],{"class":424},[411,1822,967],{"class":417},[411,1824,1825],{"class":424}," [];\n",[411,1827,1828,1831,1834,1837,1840,1843,1845,1847,1849],{"class":413,"line":524},[411,1829,1830],{"class":417},"            return",[411,1832,1833],{"class":424}," [{ kind: ",[411,1835,1836],{"class":461},"'bounced'",[411,1838,1839],{"class":424},", providerMessageId: id, at, bounceType: ",[411,1841,1842],{"class":461},"'hard'",[411,1844,1746],{"class":424},[411,1846,657],{"class":417},[411,1848,530],{"class":417},[411,1850,1851],{"class":424},"];\n",[411,1853,1854],{"class":413,"line":555},[411,1855,948],{"class":424},[411,1857,1858],{"class":413,"line":582},[411,1859,743],{"class":424},[411,1861,1862],{"class":413,"line":617},[411,1863,1049],{"class":424},[11,1865,1866,1867,355,1870,355,1873,359,1876,1879,1880,1883,1884,1887,1888,1891,1892,1895,1896,1899],{},"Das Vokabular ist ",[20,1868,1869],{},"delivered",[20,1871,1872],{},"bounced",[20,1874,1875],{},"complained",[20,1877,1878],{},"deferred"," — die Fakten, die der Versand-Lebenszyklus und die Messebene verarbeiten. Geben Sie ",[20,1881,1882],{},"[]"," zurück für einen Batch, der nichts enthält, worauf Owlat reagiert (ein Verifikations-Ping des Providers, Event-Arten, die wir ignorieren); ein Wurf wird mit ",[20,1885,1886],{},"400"," beantwortet, und der Provider stellt möglicherweise erneut zu. Jedes zurückgegebene Feld wird vom Host erneut validiert, und ",[20,1889,1890],{},"providerType"," wird aus der Registry gestempelt, sodass ein Batch sich nicht einem anderen Transport zuschreiben kann. Provider-Message-IDs in den Namensräumen, die Owlat für selbst erzeugte Nachrichten reserviert — ",[20,1893,1894],{},"pb-"," (persönliche Postbox-Mail) und ",[20,1897,1898],{},"rp-probe."," (Return-Path-Capability-Probes) —, werden aus demselben Grund abgelehnt: Die ID entscheidet, in welche Spur das Event dispatcht wird.",[11,1901,1902,1905,1906,1909,1910,1912],{},[15,1903,1904],{},"Dimensionieren Sie Ihre Batches auf diese beiden Limits."," Beide werden mit ",[20,1907,1908],{},"413"," beantwortet, ohne dass etwas angewendet wird, und ein Provider, der eine übergroße Zustellung erneut versucht, bekommt wieder ",[20,1911,1908],{},", bis er aufgibt — das darin enthaltene Feedback ist also verloren und nicht bloß verzögert. Konfigurieren Sie den Provider so, dass er stückelt; Owlat teilt nicht, was es abgelehnt hat.",[67,1914,1915,1925],{},[70,1916,1917],{},[73,1918,1919,1922],{},[76,1920,1921],{},"Limit",[76,1923,1924],{},"Obergrenze",[89,1926,1927,1938],{},[73,1928,1929,1935],{},[94,1930,1931,1932,573],{},"Request-Body (",[20,1933,1934],{},"PLUGIN_WEBHOOK_MAX_BODY_BYTES",[94,1936,1937],{},"1 048 576 Bytes UTF-8",[73,1939,1940,1946],{},[94,1941,1942,1943,573],{},"Zurückgegebene Events pro Zustellung (",[20,1944,1945],{},"PLUGIN_WEBHOOK_MAX_BATCH_EVENTS",[94,1947,1948],{},"5 000",[11,1950,1951,1952,1955,1956,1959,1960,1963,1964,1967],{},"Dieses Modul läuft im Convex-",[15,1953,1954],{},"Isolate"," (es wird vom HTTP-Router importiert) und darf daher keine Node-Builtins importieren. Rohe Request-Bodies werden nur aufbewahrt, wenn Sie ",[20,1957,1958],{},"storeRawPayload: true"," setzen — und wenn Sie das tun, wird ein verifizierter Body ",[15,1961,1962],{},"vor"," dem Lauf Ihres ",[20,1965,1966],{},"parseEvents"," gespeichert, sodass Sie genau die Zustellungen als Bytes erhalten, deren Bytes Sie am dringendsten brauchen (jene, die Ihre Parse-Hälfte abgewiesen hat).",[59,1969,1971],{"id":1970},"identität-der-versanddomain","Identität der Versanddomain",[11,1973,1974],{},"Ein Transport, dessen Provider über die Versanddomain eines Kunden informiert und gefragt werden muss, ob er für sie signieren darf, deklariert einen dritten Modul-Export an derselben Contribution:",[384,1976,1979],{"className":1977,"code":1978,"language":389,"meta":390},[387],"domainIdentity: { module: { exportPath } }\n",[20,1980,1978],{"__ignoreMap":390},[11,1982,1983,1984,1987],{},"Ein einziges Feld, denn alles andere an einer Domain-Identität gehört dem Host. Sie zu deklarieren IST ",[20,1985,1986],{},"domainVerification: 'api'"," für diese Art, und sie registriert Ihren Transport zur Kompositionszeit in der Relay-Identitäts-Registry des Hosts: Von da an fragt Sie das Routing-Gate, ob eine From-Domain über Sie relayed werden darf, das Identitäts-Backfill provisioniert Domains, die ein Betreiber früher verbunden hat, und der Alignment-Preflight bittet Sie, Ihren DKIM\u002FSPF-Arm zu beschreiben.",[11,1989,1990,1395,1993,1996,1997,2000,2001,2003],{},[15,1991,1992],{},"Zwei Aufrufe, und die Trennung ist die, die jede Identitäts-API zieht.",[20,1994,1995],{},"registerDomain"," ist der SCHREIBVORGANG — die Identität beim Provider anlegen oder bestätigen, idempotent, weil der Host bei einer expliziten Reparatur durch den Betreiber neu registriert. ",[20,1998,1999],{},"checkDomain"," ist der LESEVORGANG, den der Host nach eigenem Zeitplan wiederholt (täglich, sobald verifiziert; stündlich, solange DNS aussteht), um den Nachweis frisch zu halten. Beiden wird die aufgelöste Konfiguration des Transports übergeben, und sie müssen Credentials von dort lesen statt aus ",[20,2002,1125],{},"; und keiner darf langsam sein: Der Host ruft sie aus einer geplanten Action heraus auf, und ein hängender Aufruf ist ein nicht aufgefrischter Nachweis, der veraltet.",[11,2005,2006,1395,2009,2012,2013,2016,2017,2020,2021,2024,2025,2027],{},[15,2007,2008],{},"Drei Antworten, weil der Host jede davon anders verbucht.",[20,2010,2011],{},"ok"," trägt Beobachtungen und ist das einzige Ergebnis, das BELEG ist — das einzige, das das Alter des Nachweises auffrischt. ",[20,2014,2015],{},"auth_failed"," sagt, dass der Provider das Credential dieses Deployments abgelehnt hat: terminal, bis ein Betreiber es korrigiert, entsprechend protokolliert, und es überschreibt die bereits gespeicherten SPF\u002FDKIM-Verdikte ",[15,2018,2019],{},"nicht",", denn ein falscher API-Key ist kein Beleg dafür, dass das DNS des Betreibers ungültig geworden wäre. ",[20,2022,2023],{},"unavailable"," sagt, dass der Provider nicht geantwortet hat: Beleg für nichts, es bewegt sich also nur der Retry. Ein Modul, das wirft, wird als ",[20,2026,2023],{}," gelesen — der Host kann einen Bug in Ihrem Code nicht von einer Störung unterscheiden, und die konservative Lesart ist jene, die weder ein Credential verurteilt noch einen Nachweis auffrischt.",[384,2029,2031],{"className":405,"code":2030,"language":407,"meta":390,"style":390},"import type {\n    PluginDomainIdentityResult,\n    PluginSendTransportDomainIdentityModule,\n} from '@owlat\u002Fplugin-kit';\n\n\u002F** Observations ONLY: the host derives the status and owns the freshness bound. *\u002F\nexport const domainIdentity: PluginSendTransportDomainIdentityModule = {\n    \u002F\u002F The credential comes from the resolved configuration, never from\n    \u002F\u002F `process.env`: an environment read resolves the deployment-default instance\n    \u002F\u002F whichever instance the host meant.\n    registerDomain: (domain, config) => askProvider('POST', domain, config.env['PLUGIN_ACME_TOKEN']),\n    checkDomain: (domain, config) => askProvider('GET', domain, config.env['PLUGIN_ACME_TOKEN']),\n};\n\nasync function askProvider(\n    method: 'GET' | 'POST',\n    domain: string,\n    token: string | undefined\n): Promise\u003CPluginDomainIdentityResult> {\n    const response = await fetch(`https:\u002F\u002Fapi.example.net\u002Fdomains\u002F${domain}`, {\n        method,\n        headers: { Authorization: `Bearer ${token ?? ''}` },\n    });\n    \u002F\u002F Three distinguishable answers, because the host writes each one differently:\n    \u002F\u002F only `ok` refreshes the proof's age, and only `auth_failed` condemns a key.\n    if (response.status === 401 || response.status === 403) {\n        return { outcome: 'auth_failed', error: 'the provider rejected the token' };\n    }\n    if (!response.ok) return { outcome: 'unavailable', error: `HTTP ${response.status}` };\n    const body = (await response.json()) as {\n        readonly owned?: boolean;\n        readonly spf?: boolean;\n        readonly dkim?: boolean;\n        readonly selector?: string;\n    };\n    return {\n        outcome: 'ok',\n        state: {\n            isOwnershipVerified: body.owned === true,\n            spf: { isValid: body.spf === true },\n            dkim: { isValid: body.dkim === true },\n            dkimSelectors: body.selector ? [body.selector] : [],\n            spfMechanisms: ['include:spf.example.net'],\n        },\n    };\n}\n",[20,2032,2033,2041,2046,2051,2061,2065,2070,2088,2093,2098,2103,2137,2167,2171,2175,2187,2205,2216,2230,2245,2271,2276,2294,2299,2304,2309,2333,2351,2356,2390,2417,2432,2445,2458,2471,2476,2483,2493,2498,2510,2521,2532,2548,2559,2564,2568],{"__ignoreMap":390},[411,2034,2035,2037,2039],{"class":413,"line":414},[411,2036,418],{"class":417},[411,2038,421],{"class":417},[411,2040,425],{"class":424},[411,2042,2043],{"class":413,"line":428},[411,2044,2045],{"class":424},"    PluginDomainIdentityResult,\n",[411,2047,2048],{"class":413,"line":434},[411,2049,2050],{"class":424},"    PluginSendTransportDomainIdentityModule,\n",[411,2052,2053,2055,2057,2059],{"class":413,"line":440},[411,2054,455],{"class":424},[411,2056,458],{"class":417},[411,2058,462],{"class":461},[411,2060,465],{"class":424},[411,2062,2063],{"class":413,"line":446},[411,2064,472],{"emptyLinePlaceholder":471},[411,2066,2067],{"class":413,"line":452},[411,2068,2069],{"class":520},"\u002F** Observations ONLY: the host derives the status and owns the freshness bound. *\u002F\n",[411,2071,2072,2074,2076,2079,2081,2084,2086],{"class":413,"line":468},[411,2073,527],{"class":417},[411,2075,530],{"class":417},[411,2077,2078],{"class":500}," domainIdentity",[411,2080,497],{"class":417},[411,2082,2083],{"class":481}," PluginSendTransportDomainIdentityModule",[411,2085,651],{"class":417},[411,2087,425],{"class":424},[411,2089,2090],{"class":413,"line":475},[411,2091,2092],{"class":520},"    \u002F\u002F The credential comes from the resolved configuration, never from\n",[411,2094,2095],{"class":413,"line":487},[411,2096,2097],{"class":520},"    \u002F\u002F `process.env`: an environment read resolves the deployment-default instance\n",[411,2099,2100],{"class":413,"line":506},[411,2101,2102],{"class":520},"    \u002F\u002F whichever instance the host meant.\n",[411,2104,2105,2108,2111,2114,2116,2118,2120,2122,2125,2127,2129,2132,2134],{"class":413,"line":512},[411,2106,2107],{"class":558},"    registerDomain",[411,2109,2110],{"class":424},": (",[411,2112,2113],{"class":493},"domain",[411,2115,355],{"class":424},[411,2117,896],{"class":493},[411,2119,964],{"class":424},[411,2121,1721],{"class":417},[411,2123,2124],{"class":558}," askProvider",[411,2126,562],{"class":424},[411,2128,862],{"class":461},[411,2130,2131],{"class":424},", domain, config.env[",[411,2133,908],{"class":461},[411,2135,2136],{"class":424},"]),\n",[411,2138,2139,2142,2144,2146,2148,2150,2152,2154,2156,2158,2161,2163,2165],{"class":413,"line":517},[411,2140,2141],{"class":558},"    checkDomain",[411,2143,2110],{"class":424},[411,2145,2113],{"class":493},[411,2147,355],{"class":424},[411,2149,896],{"class":493},[411,2151,964],{"class":424},[411,2153,1721],{"class":417},[411,2155,2124],{"class":558},[411,2157,562],{"class":424},[411,2159,2160],{"class":461},"'GET'",[411,2162,2131],{"class":424},[411,2164,908],{"class":461},[411,2166,2136],{"class":424},[411,2168,2169],{"class":413,"line":524},[411,2170,1049],{"class":424},[411,2172,2173],{"class":413,"line":555},[411,2174,472],{"emptyLinePlaceholder":471},[411,2176,2177,2180,2183,2185],{"class":413,"line":582},[411,2178,2179],{"class":417},"async",[411,2181,2182],{"class":417}," function",[411,2184,2124],{"class":558},[411,2186,760],{"class":424},[411,2188,2189,2192,2194,2197,2200,2203],{"class":413,"line":617},[411,2190,2191],{"class":493},"    method",[411,2193,497],{"class":417},[411,2195,2196],{"class":461}," 'GET'",[411,2198,2199],{"class":417}," |",[411,2201,2202],{"class":461}," 'POST'",[411,2204,774],{"class":424},[411,2206,2207,2210,2212,2214],{"class":413,"line":637},[411,2208,2209],{"class":493},"    domain",[411,2211,497],{"class":417},[411,2213,501],{"class":500},[411,2215,774],{"class":424},[411,2217,2218,2221,2223,2225,2227],{"class":413,"line":643},[411,2219,2220],{"class":493},"    token",[411,2222,497],{"class":417},[411,2224,501],{"class":500},[411,2226,2199],{"class":417},[411,2228,2229],{"class":500}," undefined\n",[411,2231,2232,2234,2236,2238,2240,2243],{"class":413,"line":674},[411,2233,573],{"class":424},[411,2235,497],{"class":417},[411,2237,826],{"class":481},[411,2239,541],{"class":424},[411,2241,2242],{"class":481},"PluginDomainIdentityResult",[411,2244,834],{"class":424},[411,2246,2247,2250,2252,2254,2256,2258,2260,2263,2265,2268],{"class":413,"line":710},[411,2248,2249],{"class":417},"    const",[411,2251,842],{"class":500},[411,2253,651],{"class":417},[411,2255,847],{"class":417},[411,2257,850],{"class":558},[411,2259,562],{"class":424},[411,2261,2262],{"class":461},"`https:\u002F\u002Fapi.example.net\u002Fdomains\u002F${",[411,2264,2113],{"class":424},[411,2266,2267],{"class":461},"}`",[411,2269,2270],{"class":424},", {\n",[411,2272,2273],{"class":413,"line":726},[411,2274,2275],{"class":424},"        method,\n",[411,2277,2278,2281,2283,2286,2289,2291],{"class":413,"line":731},[411,2279,2280],{"class":424},"        headers: { Authorization: ",[411,2282,893],{"class":461},[411,2284,2285],{"class":424},"token",[411,2287,2288],{"class":417}," ??",[411,2290,917],{"class":461},[411,2292,2293],{"class":424}," },\n",[411,2295,2296],{"class":413,"line":740},[411,2297,2298],{"class":424},"    });\n",[411,2300,2301],{"class":413,"line":746},[411,2302,2303],{"class":520},"    \u002F\u002F Three distinguishable answers, because the host writes each one differently:\n",[411,2305,2306],{"class":413,"line":751},[411,2307,2308],{"class":520},"    \u002F\u002F only `ok` refreshes the proof's age, and only `auth_failed` condemns a key.\n",[411,2310,2311,2314,2316,2318,2321,2323,2326,2328,2331],{"class":413,"line":763},[411,2312,2313],{"class":417},"    if",[411,2315,956],{"class":424},[411,2317,608],{"class":417},[411,2319,2320],{"class":500}," 401",[411,2322,603],{"class":417},[411,2324,2325],{"class":424}," response.status ",[411,2327,608],{"class":417},[411,2329,2330],{"class":500}," 403",[411,2332,614],{"class":424},[411,2334,2335,2337,2340,2343,2346,2349],{"class":413,"line":777},[411,2336,734],{"class":417},[411,2338,2339],{"class":424}," { outcome: ",[411,2341,2342],{"class":461},"'auth_failed'",[411,2344,2345],{"class":424},", error: ",[411,2347,2348],{"class":461},"'the provider rejected the token'",[411,2350,982],{"class":424},[411,2352,2353],{"class":413,"line":789},[411,2354,2355],{"class":424},"    }\n",[411,2357,2358,2360,2362,2364,2366,2368,2370,2373,2375,2378,2381,2383,2386,2388],{"class":413,"line":795},[411,2359,2313],{"class":417},[411,2361,588],{"class":424},[411,2363,992],{"class":417},[411,2365,995],{"class":424},[411,2367,967],{"class":417},[411,2369,2339],{"class":424},[411,2371,2372],{"class":461},"'unavailable'",[411,2374,2345],{"class":424},[411,2376,2377],{"class":461},"`HTTP ${",[411,2379,2380],{"class":424},"response",[411,2382,899],{"class":461},[411,2384,2385],{"class":424},"status",[411,2387,2267],{"class":461},[411,2389,982],{"class":424},[411,2391,2392,2394,2397,2399,2401,2404,2407,2410,2413,2415],{"class":413,"line":801},[411,2393,2249],{"class":417},[411,2395,2396],{"class":500}," body",[411,2398,651],{"class":417},[411,2400,588],{"class":424},[411,2402,2403],{"class":417},"await",[411,2405,2406],{"class":424}," response.",[411,2408,2409],{"class":558},"json",[411,2411,2412],{"class":424},"()) ",[411,2414,657],{"class":417},[411,2416,425],{"class":424},[411,2418,2419,2422,2425,2427,2430],{"class":413,"line":807},[411,2420,2421],{"class":417},"        readonly",[411,2423,2424],{"class":493}," owned",[411,2426,666],{"class":417},[411,2428,2429],{"class":500}," boolean",[411,2431,465],{"class":424},[411,2433,2434,2436,2439,2441,2443],{"class":413,"line":818},[411,2435,2421],{"class":417},[411,2437,2438],{"class":493}," spf",[411,2440,666],{"class":417},[411,2442,2429],{"class":500},[411,2444,465],{"class":424},[411,2446,2447,2449,2452,2454,2456],{"class":413,"line":837},[411,2448,2421],{"class":417},[411,2450,2451],{"class":493}," dkim",[411,2453,666],{"class":417},[411,2455,2429],{"class":500},[411,2457,465],{"class":424},[411,2459,2460,2462,2465,2467,2469],{"class":413,"line":856},[411,2461,2421],{"class":417},[411,2463,2464],{"class":493}," selector",[411,2466,666],{"class":417},[411,2468,501],{"class":500},[411,2470,465],{"class":424},[411,2472,2473],{"class":413,"line":867},[411,2474,2475],{"class":424},"    };\n",[411,2477,2478,2481],{"class":413,"line":873},[411,2479,2480],{"class":417},"    return",[411,2482,425],{"class":424},[411,2484,2485,2488,2491],{"class":413,"line":887},[411,2486,2487],{"class":424},"        outcome: ",[411,2489,2490],{"class":461},"'ok'",[411,2492,774],{"class":424},[411,2494,2495],{"class":413,"line":922},[411,2496,2497],{"class":424},"        state: {\n",[411,2499,2500,2503,2505,2508],{"class":413,"line":928},[411,2501,2502],{"class":424},"            isOwnershipVerified: body.owned ",[411,2504,608],{"class":417},[411,2506,2507],{"class":500}," true",[411,2509,774],{"class":424},[411,2511,2512,2515,2517,2519],{"class":413,"line":945},[411,2513,2514],{"class":424},"            spf: { isValid: body.spf ",[411,2516,608],{"class":417},[411,2518,2507],{"class":500},[411,2520,2293],{"class":424},[411,2522,2523,2526,2528,2530],{"class":413,"line":951},[411,2524,2525],{"class":424},"            dkim: { isValid: body.dkim ",[411,2527,608],{"class":417},[411,2529,2507],{"class":500},[411,2531,2293],{"class":424},[411,2533,2534,2537,2540,2543,2545],{"class":413,"line":985},[411,2535,2536],{"class":424},"            dkimSelectors: body.selector ",[411,2538,2539],{"class":417},"?",[411,2541,2542],{"class":424}," [body.selector] ",[411,2544,497],{"class":417},[411,2546,2547],{"class":424}," [],\n",[411,2549,2550,2553,2556],{"class":413,"line":1011},[411,2551,2552],{"class":424},"            spfMechanisms: [",[411,2554,2555],{"class":461},"'include:spf.example.net'",[411,2557,2558],{"class":424},"],\n",[411,2560,2561],{"class":413,"line":1041},[411,2562,2563],{"class":424},"        },\n",[411,2565,2566],{"class":413,"line":1046},[411,2567,2475],{"class":424},[411,2569,2571],{"class":413,"line":2570},46,[411,2572,509],{"class":424},[11,2574,2575,2578,2579,2581,2582,2585],{},[15,2576,2577],{},"Sie melden Beobachtungen, der Host entscheidet."," Es gibt kein ",[20,2580,2385],{},"-Feld, das Sie zurückgeben könnten. Owlat leitet ihn aus Ihren drei Beobachtungen ab — Ownership bestätigt, SPF gültig, DKIM gültig und mindestens ein auflösbarer Selector —, damit „verifiziert“ auf jeder Relay-Stufe dasselbe bedeutet und ein Modul eine Domain nicht als verifiziert melden kann, während es uns mitteilt, dass ihr DKIM-Record ungültig ist. Die Frischegrenze ist eine Host-Konstante (",[20,2583,2584],{},"PLUGIN_RELAY_PROOF_MAX_AGE_MS",", sieben Tage) und kein Manifest-Feld: Sie ist das Einzige, was einen Nachweis für eine auf Ihrer Seite widerrufene Identität außer Kraft setzt, während unsere Zeile fortbesteht — ein deklarierbares Fenster wäre also eine deklarierbare Aufweichung davon. Wo die Identitätszeile liegt, was ein fehlgeschlagener Aufruf überschreiben darf und wann erneut gefragt wird, gehört ebenfalls dem Host.",[11,2587,2588,359,2591,2594,2595,2597,2598,2601,2602,2604,2605,2608,2609,2612,2613,2616,2617,2620],{},[20,2589,2590],{},"dkimSelectors",[20,2592,2593],{},"spfMechanisms"," werden am STATE mitgeführt statt im Manifest deklariert, weil beide Provider-Formen real sind — ein gemeinsamer, kontoweiter Selector oder Tokens je Domain, die erst nach der Registrierung existieren. Sie sind das, was der Alignment-Preflight für Dual-Transport live auflöst. Die beiden leeren Listen bedeuten NICHT dasselbe, deshalb lohnt Genauigkeit: Keine ",[20,2596,2590],{}," bedeutet „wir können die Signaturidentität dieser Domain nicht beschreiben“, und das ist ein HOLD für die Ramp und niemals ein geöffnetes Gate (die Domain erreicht ",[20,2599,2600],{},"verified"," nicht, und es wird kein Referenzarm für sie beschrieben). Keine ",[20,2603,2593],{}," bedeutet „dieses Relay benötigt keine SPF-Autorisierung auf der From-Domain des Kunden“ — der Preflight führt Ihre Mechanismen mit denen der eigenen MTA zu einem erforderlichen Satz zusammen, keine beizutragen lässt Ihre Anforderung also schlicht entfallen, und die SPF-Prüfung kann auf einem Record bestehen, der Sie nicht nennt. Geben Sie sie zurück, wann immer Sie sie kennen; ein gemeinsames Include, das Sie nicht aus Ihrer API auslesen können, ist besser hart kodiert als weggelassen. Höchstens 8 je Liste (",[20,2606,2607],{},"PLUGIN_DOMAIN_IDENTITY_MAX_DNS_FACTS","), jeweils höchstens 255 Zeichen (",[20,2610,2611],{},"PLUGIN_DOMAIN_IDENTITY_MAX_DNS_FACT_LENGTH","), und alles darüber wird verworfen statt abgelehnt. Der ",[20,2614,2615],{},"error"," bei einem fehlgeschlagenen Ergebnis oder einem ungültigen Record ist freier Text des Providers, der ausschließlich für eine Betreiber-Logzeile aufbewahrt, bei 500 Zeichen abgeschnitten (",[20,2618,2619],{},"PLUGIN_DOMAIN_IDENTITY_MAX_ERROR_LENGTH",") und nie als Handlungsanweisung gerendert wird.",[11,2622,2623,2624,2627,2628,2630,2631,2634],{},"Wie die Webhook-Hälfte wird auch dieses Modul von Code auf dem Enqueue-Pfad importiert und darf keine Node-Builtins importieren; seine Aufrufe sind HTTP, und ",[20,2625,2626],{},"fetch"," steht zur Verfügung. Jeder Aufruf wird zuvor erneut autorisiert — Flag an, ",[20,2629,103],{}," weiterhin gewährt, Konfiguration vorhanden — und als ",[20,2632,2633],{},"transport.domain_identity"," auditiert, weil er das Credential dieses Deployments bei Ihrem Provider unter dem Domainnamen eines Kunden einsetzt. Das Plugin abzuschalten stoppt ihn, sichtbar.",[54,2636,2638],{"id":2637},"agent-schritte","Agent-Schritte",[384,2640,2643],{"className":2641,"code":2642,"language":389,"meta":390},[387],"agentSteps: [{ id, after, module: { exportPath }, lifecycleEdges: [] }]\n",[20,2644,2642],{"__ignoreMap":390},[11,2646,2647,2650,2651,355,2654,355,2657,355,2660,355,2663,2666],{},[20,2648,2649],{},"after"," ist ein Kern-Schritt (",[20,2652,2653],{},"security_scan",[20,2655,2656],{},"context_retrieval",[20,2658,2659],{},"classify",[20,2661,2662],{},"clarify",[20,2664,2665],{},"draft",") oder ein anderer Plugin-Schritt. Die Codegen weist unbekannte oder terminale Anker, doppelte Arten, Einfügezyklen und Kanten außerhalb der ausschließlich einschränkenden Policy des Hosts zurück.",[384,2668,2670],{"className":405,"code":2669,"language":407,"meta":390,"style":390},"import type {\n    PluginAgentStepInput,\n    PluginAgentStepModule,\n    PluginAgentStepResult,\n} from '@owlat\u002Fplugin-kit';\n\nexport const agentStep: PluginAgentStepModule = {\n    async execute(input: PluginAgentStepInput): Promise\u003CPluginAgentStepResult> {\n        if (input.subject.toLowerCase().startsWith('[auto-reply]')) {\n            \u002F\u002F Restrict-only: a step may request a DECLARED caution edge, but never\n            \u002F\u002F choose the next step, approve, or send.\n            return { kind: 'caution', to: 'archived', reason: 'vendor auto-reply' };\n        }\n        return { kind: 'continue' };\n    },\n};\n",[20,2671,2672,2680,2685,2690,2695,2705,2709,2727,2756,2778,2783,2788,2812,2816,2827,2831],{"__ignoreMap":390},[411,2673,2674,2676,2678],{"class":413,"line":414},[411,2675,418],{"class":417},[411,2677,421],{"class":417},[411,2679,425],{"class":424},[411,2681,2682],{"class":413,"line":428},[411,2683,2684],{"class":424},"    PluginAgentStepInput,\n",[411,2686,2687],{"class":413,"line":434},[411,2688,2689],{"class":424},"    PluginAgentStepModule,\n",[411,2691,2692],{"class":413,"line":440},[411,2693,2694],{"class":424},"    PluginAgentStepResult,\n",[411,2696,2697,2699,2701,2703],{"class":413,"line":446},[411,2698,455],{"class":424},[411,2700,458],{"class":417},[411,2702,462],{"class":461},[411,2704,465],{"class":424},[411,2706,2707],{"class":413,"line":452},[411,2708,472],{"emptyLinePlaceholder":471},[411,2710,2711,2713,2715,2718,2720,2723,2725],{"class":413,"line":468},[411,2712,527],{"class":417},[411,2714,530],{"class":417},[411,2716,2717],{"class":500}," agentStep",[411,2719,497],{"class":417},[411,2721,2722],{"class":481}," PluginAgentStepModule",[411,2724,651],{"class":417},[411,2726,425],{"class":424},[411,2728,2729,2731,2734,2736,2738,2740,2743,2745,2747,2749,2751,2754],{"class":413,"line":475},[411,2730,754],{"class":417},[411,2732,2733],{"class":558}," execute",[411,2735,562],{"class":424},[411,2737,565],{"class":493},[411,2739,497],{"class":417},[411,2741,2742],{"class":481}," PluginAgentStepInput",[411,2744,573],{"class":424},[411,2746,497],{"class":417},[411,2748,826],{"class":481},[411,2750,541],{"class":424},[411,2752,2753],{"class":481},"PluginAgentStepResult",[411,2755,834],{"class":424},[411,2757,2758,2760,2763,2766,2769,2771,2773,2776],{"class":413,"line":487},[411,2759,585],{"class":417},[411,2761,2762],{"class":424}," (input.subject.",[411,2764,2765],{"class":558},"toLowerCase",[411,2767,2768],{"class":424},"().",[411,2770,699],{"class":558},[411,2772,562],{"class":424},[411,2774,2775],{"class":461},"'[auto-reply]'",[411,2777,707],{"class":424},[411,2779,2780],{"class":413,"line":506},[411,2781,2782],{"class":520},"            \u002F\u002F Restrict-only: a step may request a DECLARED caution edge, but never\n",[411,2784,2785],{"class":413,"line":512},[411,2786,2787],{"class":520},"            \u002F\u002F choose the next step, approve, or send.\n",[411,2789,2790,2792,2795,2798,2801,2804,2807,2810],{"class":413,"line":517},[411,2791,1830],{"class":417},[411,2793,2794],{"class":424}," { kind: ",[411,2796,2797],{"class":461},"'caution'",[411,2799,2800],{"class":424},", to: ",[411,2802,2803],{"class":461},"'archived'",[411,2805,2806],{"class":424},", reason: ",[411,2808,2809],{"class":461},"'vendor auto-reply'",[411,2811,982],{"class":424},[411,2813,2814],{"class":413,"line":524},[411,2815,640],{"class":424},[411,2817,2818,2820,2822,2825],{"class":413,"line":555},[411,2819,734],{"class":417},[411,2821,2794],{"class":424},[411,2823,2824],{"class":461},"'continue'",[411,2826,982],{"class":424},[411,2828,2829],{"class":413,"line":582},[411,2830,743],{"class":424},[411,2832,2833],{"class":413,"line":617},[411,2834,1049],{"class":424},[11,2836,2837,2838,2841],{},"Fünf der sechs eingebauten Schritte bilden auf drei host-eigene Platzierungen ab; der sechste, der terminale ",[20,2839,2840],{},"route","-Schritt, hat keine Platzierung und kann nicht als Anker dienen:",[67,2843,2844,2857],{},[70,2845,2846],{},[73,2847,2848,2851,2854],{},[76,2849,2850],{},"Platzierung",[76,2852,2853],{},"Anker",[76,2855,2856],{},"Kanten, die ein Nachfolger anfordern darf",[89,2858,2859,2880,2900],{},[73,2860,2861,2866,2869],{},[94,2862,2863],{},[20,2864,2865],{},"classification",[94,2867,2868],{},"Security-Scan, Context-Retrieval, Classify",[94,2870,2871,355,2874,2876,2877],{},[20,2872,2873],{},"archived",[20,2875,184],{}," aus ",[20,2878,2879],{},"classifying",[73,2881,2882,2887,2890],{},[94,2883,2884],{},[20,2885,2886],{},"before_draft",[94,2888,2889],{},"Clarify",[94,2891,2892,355,2894,2876,2896,2899],{},[20,2893,2873],{},[20,2895,184],{},[20,2897,2898],{},"drafting"," (es ist noch nicht garantiert, dass ein Entwurf existiert)",[73,2901,2902,2907,2910],{},[94,2903,2904],{},[20,2905,2906],{},"after_draft",[94,2908,2909],{},"Draft",[94,2911,2912,355,2914,2916,2917],{},[20,2913,2873],{},[20,2915,184],{}," und die Review-Kante ",[20,2918,2919],{},"drafting → draft_ready",[11,2921,2922,2923,2926,2927,2930],{},"Ein Plugin, das hinter ein anderes Plugin gekettet wird, erbt dessen Platzierung. Kein Plugin darf ",[20,2924,2925],{},"approved"," oder ",[20,2928,2929],{},"sent"," anfordern, den nächsten Schritt wählen, vor dem Security-Scan laufen oder den Kern-Legalitätsgraphen bearbeiten. Der Walker nimmt stets die ursprüngliche Kern-Fortsetzung wieder auf; ungültige Ausgaben oder eine Exception lassen den Lebenszyklus fail-closed scheitern.",[54,2932,2934],{"id":2933},"draft-strategien","Draft-Strategien",[384,2936,2939],{"className":2937,"code":2938,"language":389,"meta":390},[387],"draftStrategies: [{ id, label, module: { exportPath }, timeoutMs \u002F* ≤ 30 000 *\u002F }]\n",[20,2940,2938],{"__ignoreMap":390},[11,2942,2943,2944,2946,2947,2949,2950,2952,2953,2956],{},"Eine Strategie ersetzt ",[15,2945,1118],{}," die primäre Generierung. Die Auswahlreihenfolge ist Kontakt, dann Postfach, dann Klassifikation, dann die eingebaute ",[20,2948,146],{},"-Strategie. Das Modul erhält eine eingefrorene, begrenzte Projektion plus den attribuierten, budgetierten LLM-Service (der separat ",[20,2951,354],{}," erfordert) und gibt ",[20,2954,2955],{},"{ draftBody }"," zurück.",[11,2958,2959,2960,2962],{},"Owlat hält das Injection-Scanning des zusammengestellten Kontexts, den Qualitäts-Selbstcheck, die Review-Optionen, die Persistenz, das Routing, die Autonomie und den Versand außerhalb der Strategie. Verweigerung, Timeout, Fehlschlag, veraltete Auswahl oder fehlerhafte\u002Fübergroße\u002Finjection-artige Ausgaben fallen alle einmalig auf ",[20,2961,146],{}," zurück. Siehe ADR-0050.",[54,2964,2966,2967,573],{"id":2965},"autonomy-gates-sendgates","Autonomy-Gates (",[20,2968,154],{},[384,2970,2973],{"className":2971,"code":2972,"language":389,"meta":390},[387],"sendGates: [{ id, label, module: { exportPath }, timeoutMs \u002F* ≤ 30 000 *\u002F }]\n",[20,2974,2972],{"__ignoreMap":390},[11,2976,2977,2978,2981,2982,2985],{},"Plugin-Gates laufen ",[15,2979,2980],{},"nach"," jedem unveränderlichen Kern-Gate zur Route-Zeit, in der generierten Katalogreihenfolge, einmal an der Freigabegrenze zur Route-Zeit. Das Modul erhält eine eingefrorene, begrenzte Mail-Projektion und ein ",[20,2983,2984],{},"AbortSignal"," — keinen Host-Service, kein Credential, keinen Convex-Context.",[11,2987,2988,2989,2926,2992,2995],{},"Der Ergebnistyp ist strukturell nicht in der Lage, eine Freigabe auszudrücken: ",[20,2990,2991],{},"{ outcome: 'no-objection' }",[20,2993,2994],{},"{ outcome: 'objection', reason }",". Deaktivierte, widerrufene, veraltete, fehlende, abgelaufene, fehlgeschlagene oder fehlerhafte Gates leiten die Antwort konservativ in die menschliche Prüfung. Das Audit hält ausschließlich feste Operations-\u002FErgebnis-\u002FBegründungscodes fest. Siehe ADR-0051.",[54,2997,2999],{"id":2998},"automationen","Automationen",[384,3001,3004],{"className":3002,"code":3003,"language":389,"meta":390},[387],"automationTriggers: [{ id, label, description, icon, module: { exportPath } }]\nautomationSteps:    [{ id, label, description, icon, module: { exportPath } }]\nautomationConditions: [{ id, label, description, icon, module: { exportPath } }]\n",[20,3005,3003],{"__ignoreMap":390},[11,3007,3008],{},"Jede Registry hat ihre eigene Capability, sodass eine Grant die eine ohne die anderen freischalten kann. Editor-Metadaten werden wortgleich in den generierten Katalog kopiert, damit der Automation-Builder eine Contribution rendern kann, ohne Plugin-Code zu importieren; das Frontend behandelt sie weiterhin als nicht vertrauenswürdigen Text.",[384,3010,3012],{"className":405,"code":3011,"language":407,"meta":390,"style":390},"import type {\n    PluginAutomationStepInput,\n    PluginAutomationStepModule,\n    PluginAutomationStepResult,\n} from '@owlat\u002Fplugin-kit';\n\ninterface NotifyConfig {\n    readonly channel: string;\n}\n\nexport const automationStep: PluginAutomationStepModule\u003CNotifyConfig> = {\n    parseConfig(raw: unknown): NotifyConfig {\n        const channel = (raw as { channel?: unknown } | null)?.channel;\n        if (typeof channel !== 'string' || channel.length === 0) {\n            throw new TypeError('config.channel is required');\n        }\n        return { channel };\n    },\n\n    async execute(\n        input: PluginAutomationStepInput,\n        config: NotifyConfig\n    ): Promise\u003CPluginAutomationStepResult> {\n        if (!input.contactEmail.includes('@')) {\n            return { kind: 'failed', reason: 'contact has no address' };\n        }\n        await Promise.resolve(config.channel);\n        return { kind: 'completed' };\n    },\n};\n",[20,3013,3014,3022,3027,3032,3037,3047,3051,3060,3073,3077,3081,3106,3128,3160,3191,3206,3210,3217,3221,3225,3233,3245,3254,3269,3290,3306,3310,3325,3336,3340],{"__ignoreMap":390},[411,3015,3016,3018,3020],{"class":413,"line":414},[411,3017,418],{"class":417},[411,3019,421],{"class":417},[411,3021,425],{"class":424},[411,3023,3024],{"class":413,"line":428},[411,3025,3026],{"class":424},"    PluginAutomationStepInput,\n",[411,3028,3029],{"class":413,"line":434},[411,3030,3031],{"class":424},"    PluginAutomationStepModule,\n",[411,3033,3034],{"class":413,"line":440},[411,3035,3036],{"class":424},"    PluginAutomationStepResult,\n",[411,3038,3039,3041,3043,3045],{"class":413,"line":446},[411,3040,455],{"class":424},[411,3042,458],{"class":417},[411,3044,462],{"class":461},[411,3046,465],{"class":424},[411,3048,3049],{"class":413,"line":452},[411,3050,472],{"emptyLinePlaceholder":471},[411,3052,3053,3055,3058],{"class":413,"line":468},[411,3054,478],{"class":417},[411,3056,3057],{"class":481}," NotifyConfig",[411,3059,425],{"class":424},[411,3061,3062,3064,3067,3069,3071],{"class":413,"line":475},[411,3063,490],{"class":417},[411,3065,3066],{"class":493}," channel",[411,3068,497],{"class":417},[411,3070,501],{"class":500},[411,3072,465],{"class":424},[411,3074,3075],{"class":413,"line":487},[411,3076,509],{"class":424},[411,3078,3079],{"class":413,"line":506},[411,3080,472],{"emptyLinePlaceholder":471},[411,3082,3083,3085,3087,3090,3092,3095,3097,3100,3102,3104],{"class":413,"line":512},[411,3084,527],{"class":417},[411,3086,530],{"class":417},[411,3088,3089],{"class":500}," automationStep",[411,3091,497],{"class":417},[411,3093,3094],{"class":481}," PluginAutomationStepModule",[411,3096,541],{"class":424},[411,3098,3099],{"class":481},"NotifyConfig",[411,3101,547],{"class":424},[411,3103,550],{"class":417},[411,3105,425],{"class":424},[411,3107,3108,3111,3113,3116,3118,3120,3122,3124,3126],{"class":413,"line":517},[411,3109,3110],{"class":558},"    parseConfig",[411,3112,562],{"class":424},[411,3114,3115],{"class":493},"raw",[411,3117,497],{"class":417},[411,3119,570],{"class":500},[411,3121,573],{"class":424},[411,3123,497],{"class":417},[411,3125,3057],{"class":481},[411,3127,425],{"class":424},[411,3129,3130,3132,3134,3136,3139,3141,3143,3146,3148,3150,3152,3155,3157],{"class":413,"line":524},[411,3131,646],{"class":417},[411,3133,3066],{"class":500},[411,3135,651],{"class":417},[411,3137,3138],{"class":424}," (raw ",[411,3140,657],{"class":417},[411,3142,660],{"class":424},[411,3144,3145],{"class":493},"channel",[411,3147,666],{"class":417},[411,3149,570],{"class":500},[411,3151,1746],{"class":424},[411,3153,3154],{"class":417},"|",[411,3156,611],{"class":500},[411,3158,3159],{"class":424},")?.channel;\n",[411,3161,3162,3164,3166,3168,3171,3173,3175,3177,3180,3183,3186,3189],{"class":413,"line":555},[411,3163,585],{"class":417},[411,3165,588],{"class":424},[411,3167,591],{"class":417},[411,3169,3170],{"class":424}," channel ",[411,3172,597],{"class":417},[411,3174,688],{"class":461},[411,3176,603],{"class":417},[411,3178,3179],{"class":424}," channel.",[411,3181,3182],{"class":500},"length",[411,3184,3185],{"class":417}," ===",[411,3187,3188],{"class":500}," 0",[411,3190,614],{"class":424},[411,3192,3193,3195,3197,3199,3201,3204],{"class":413,"line":582},[411,3194,620],{"class":417},[411,3196,623],{"class":417},[411,3198,626],{"class":558},[411,3200,562],{"class":424},[411,3202,3203],{"class":461},"'config.channel is required'",[411,3205,634],{"class":424},[411,3207,3208],{"class":413,"line":617},[411,3209,640],{"class":424},[411,3211,3212,3214],{"class":413,"line":637},[411,3213,734],{"class":417},[411,3215,3216],{"class":424}," { channel };\n",[411,3218,3219],{"class":413,"line":643},[411,3220,743],{"class":424},[411,3222,3223],{"class":413,"line":674},[411,3224,472],{"emptyLinePlaceholder":471},[411,3226,3227,3229,3231],{"class":413,"line":710},[411,3228,754],{"class":417},[411,3230,2733],{"class":558},[411,3232,760],{"class":424},[411,3234,3235,3238,3240,3243],{"class":413,"line":726},[411,3236,3237],{"class":493},"        input",[411,3239,497],{"class":417},[411,3241,3242],{"class":481}," PluginAutomationStepInput",[411,3244,774],{"class":424},[411,3246,3247,3249,3251],{"class":413,"line":731},[411,3248,810],{"class":493},[411,3250,497],{"class":417},[411,3252,3253],{"class":481}," NotifyConfig\n",[411,3255,3256,3258,3260,3262,3264,3267],{"class":413,"line":740},[411,3257,821],{"class":424},[411,3259,497],{"class":417},[411,3261,826],{"class":481},[411,3263,541],{"class":424},[411,3265,3266],{"class":481},"PluginAutomationStepResult",[411,3268,834],{"class":424},[411,3270,3271,3273,3275,3277,3280,3283,3285,3288],{"class":413,"line":746},[411,3272,585],{"class":417},[411,3274,588],{"class":424},[411,3276,992],{"class":417},[411,3278,3279],{"class":424},"input.contactEmail.",[411,3281,3282],{"class":558},"includes",[411,3284,562],{"class":424},[411,3286,3287],{"class":461},"'@'",[411,3289,707],{"class":424},[411,3291,3292,3294,3296,3299,3301,3304],{"class":413,"line":751},[411,3293,1830],{"class":417},[411,3295,2794],{"class":424},[411,3297,3298],{"class":461},"'failed'",[411,3300,2806],{"class":424},[411,3302,3303],{"class":461},"'contact has no address'",[411,3305,982],{"class":424},[411,3307,3308],{"class":413,"line":763},[411,3309,640],{"class":424},[411,3311,3312,3315,3317,3319,3322],{"class":413,"line":777},[411,3313,3314],{"class":417},"        await",[411,3316,826],{"class":500},[411,3318,899],{"class":424},[411,3320,3321],{"class":558},"resolve",[411,3323,3324],{"class":424},"(config.channel);\n",[411,3326,3327,3329,3331,3334],{"class":413,"line":789},[411,3328,734],{"class":417},[411,3330,2794],{"class":424},[411,3332,3333],{"class":461},"'completed'",[411,3335,982],{"class":424},[411,3337,3338],{"class":413,"line":795},[411,3339,743],{"class":424},[411,3341,3342],{"class":413,"line":801},[411,3343,1049],{"class":424},[11,3345,3346,3347,3350],{},"Der Step-Walker besitzt Retries, den idempotenten Claim, den Abbruch und den Circuit Breaker; der gehostete Runner besitzt genau einen autorisierten Versuch mit einer host-eigenen 30-Sekunden-Deadline. Ein Plugin-Schritt kann abschließen oder fehlschlagen — er kann niemals erzwingen, dass ein Lauf fortschreitet. Fehlerbegründungen werden beschnitten und von Steuerzeichen befreit, bevor sie ",[20,3348,3349],{},"errorMessage"," erreichen.",[11,3352,3353,3354,3357,3358,3361,3362,3365,3366,3369],{},"Trigger ",[1185,3355,3356],{},"entscheiden"," lediglich, ob ein Auslösen eine Automation startet; das Auffächern übernimmt der Host. Die Konfiguration eines Plugin-Triggers reist auf einem ",[20,3359,3360],{},"{ pluginConfig }","-Arm und wird vor ",[20,3363,3364],{},"parseConfig"," ausgepackt, und die Ausgabe von ",[20,3367,3368],{},"buildTriggerData"," wird auf begrenzte primitive Keys beschnitten, bevor sie die Run-Zeile erreicht. Conditions sind vertraglich verpflichtet, synchron innerhalb einer Query auszuwerten.",[3371,3372,3375],"callout",{"title":3373,"type":3374},"Heute läuft nur `automationSteps`","warning",[11,3376,3377,3378,3380,3381,305,3383,3385],{},"Von den drei Automation-Registries wird nur ",[20,3379,171],{}," dispatcht. Es gibt weder eine Naht zum Auslösen von Plugin-Triggern noch einen Plugin-Condition-Evaluator: ",[20,3382,304],{},[20,3384,308],{},"-Art, statt „trifft nicht zu“ zurückzugeben, und kein Condition-Art-Validator lässt zu, dass eine solche in einem Segmentfilter persistiert wird. Katalog- und Capability-Obergrenzen sind reserviert; ausführbare Host-Pfade werden nicht vor einem Produzenten ausgeliefert.",[54,3387,3389],{"id":3388},"webhook-events","Webhook-Events",[384,3391,3394],{"className":3392,"code":3393,"language":389,"meta":390},[387],"webhookEvents: [{ id, description, subscribable }]\n",[20,3395,3393],{"__ignoreMap":390},[11,3397,3398,3399,355,3402,3405,3406,1368,3408,3411],{},"Nur Daten — das Plugin liefert für das Event keinen ausführbaren Code aus. Kern-Events behalten flache Literale (",[20,3400,3401],{},"email.sent",[20,3403,3404],{},"contact.created","); Plugin-Events sind ",[20,3407,51],{},[20,3409,3410],{},"subscribable: false"," bedeutet, dass Kunden-Endpunkte nicht abonnieren können und das Event immer nur an ein einzelnes explizites Ziel zugestellt wird. Payload-Daten, die dem Host beim Emit übergeben werden, sind nicht vertrauenswürdig und werden vor der Zustellung beschnitten und bereinigt.",[3371,3413,3415],{"title":3414,"type":3374},"Noch kein Publish-Pfad",[11,3416,3417,3418,3420],{},"Der komponierte Event-Katalog existiert, aber es wird weder eine Publish- noch eine Autorisierungsnaht ausgeliefert: Die Validatoren für persistierte Webhook-Events sind handaufgezählte, geschlossene Unions, die an die Kern-Registry gebunden sind — eine ",[20,3419,308],{},"-Event-Art kann also nicht an einem Endpunkt-Abonnement gespeichert werden und wird nie zugestellt. Den Bucket zu deklarieren ist heute wirkungslos.",[54,3422,3424],{"id":3423},"import-provider","Import-Provider",[384,3426,3429],{"className":3427,"code":3428,"language":389,"meta":390},[387],"importProviders: [{ id, label, module: { exportPath }, signature, attestSource? }]\n",[20,3430,3428],{"__ignoreMap":390},[11,3432,3433,3435,3436,879,3439,3442],{},[20,3434,1518],{}," ist ",[15,3437,3438],{},"erforderlich",[20,3440,3441],{},"{ header, algorithm: 'hmac-sha256' | 'hmac-sha1', encoding: 'hex' | 'base64', secretEnvVar }",". Der Host liest das Secret aus der Umgebungsvariable, berechnet den HMAC über den rohen Body neu und vergleicht in konstanter Zeit. Die Verifikation schlägt fail-closed fehl, wenn das Secret nicht gesetzt ist oder der Header fehlt, fehlerhaft ist oder nicht übereinstimmt — ein Plugin kann sich dem nicht entziehen.",[3371,3444,3446],{"title":3445,"type":3374},"Nur Herkunft, keine Replay-Resistenz",[11,3447,3448,3449,3453],{},"Der Signaturvertrag signiert allein den rohen Body — kein Zeitstempel, keine Toleranz, keine Nonce —, sein Bestehen beweist also Herkunft, nicht Aktualität. Er sichert heute keinen HTTP-Endpunkt ab. Das Stück, das eine eingehende HTTP-Fläche verdrahtet, muss zuvor eine Replay-Abwehr darüberlegen, bevor irgendein Endpunkt plugin-stämmigen Traffic annimmt. Zum Vergleich die ",[369,3450,3452],{"href":3451},"\u002Fdeveloper\u002Fplugin-connected-apps","signierten Hooks"," von Tier 2, die sehr wohl einen Zeitstempel und eine Nonce signieren.",[384,3455,3457],{"className":405,"code":3456,"language":407,"meta":390,"style":390},"import type {\n    JsonObject,\n    PluginImportPageResult,\n    PluginImportProviderInput,\n    PluginImportProviderModule,\n} from '@owlat\u002Fplugin-kit';\n\nexport const importProvider: PluginImportProviderModule = {\n    validateConfig(config: JsonObject) {\n        return typeof config['listId'] === 'string'\n            ? ({ ok: true } as const)\n            : ({ ok: false, reason: 'listId is required' } as const);\n    },\n\n    async fetchPage(input: PluginImportProviderInput): Promise\u003CPluginImportPageResult> {\n        \u002F\u002F `cursor` is `''` on the first page; return `null` to end the walk.\n        const page = input.cursor === '' ? 1 : Number(input.cursor);\n        return {\n            rows: [{ email: `contact-${page}@example.com`, fields: { source: 'vendor' } }],\n            nextCursor: page >= 2 ? null : String(page + 1),\n        };\n    },\n};\n",[20,3458,3459,3467,3472,3477,3482,3487,3497,3501,3519,3535,3554,3573,3595,3599,3603,3632,3637,3668,3674,3697,3728,3733,3737],{"__ignoreMap":390},[411,3460,3461,3463,3465],{"class":413,"line":414},[411,3462,418],{"class":417},[411,3464,421],{"class":417},[411,3466,425],{"class":424},[411,3468,3469],{"class":413,"line":428},[411,3470,3471],{"class":424},"    JsonObject,\n",[411,3473,3474],{"class":413,"line":434},[411,3475,3476],{"class":424},"    PluginImportPageResult,\n",[411,3478,3479],{"class":413,"line":440},[411,3480,3481],{"class":424},"    PluginImportProviderInput,\n",[411,3483,3484],{"class":413,"line":446},[411,3485,3486],{"class":424},"    PluginImportProviderModule,\n",[411,3488,3489,3491,3493,3495],{"class":413,"line":452},[411,3490,455],{"class":424},[411,3492,458],{"class":417},[411,3494,462],{"class":461},[411,3496,465],{"class":424},[411,3498,3499],{"class":413,"line":468},[411,3500,472],{"emptyLinePlaceholder":471},[411,3502,3503,3505,3507,3510,3512,3515,3517],{"class":413,"line":475},[411,3504,527],{"class":417},[411,3506,530],{"class":417},[411,3508,3509],{"class":500}," importProvider",[411,3511,497],{"class":417},[411,3513,3514],{"class":481}," PluginImportProviderModule",[411,3516,651],{"class":417},[411,3518,425],{"class":424},[411,3520,3521,3524,3526,3528,3530,3533],{"class":413,"line":487},[411,3522,3523],{"class":558},"    validateConfig",[411,3525,562],{"class":424},[411,3527,896],{"class":493},[411,3529,497],{"class":417},[411,3531,3532],{"class":481}," JsonObject",[411,3534,614],{"class":424},[411,3536,3537,3539,3541,3544,3547,3549,3551],{"class":413,"line":506},[411,3538,734],{"class":417},[411,3540,1799],{"class":417},[411,3542,3543],{"class":424}," config[",[411,3545,3546],{"class":461},"'listId'",[411,3548,911],{"class":424},[411,3550,608],{"class":417},[411,3552,3553],{"class":461}," 'string'\n",[411,3555,3556,3559,3562,3564,3566,3568,3570],{"class":413,"line":512},[411,3557,3558],{"class":417},"            ?",[411,3560,3561],{"class":424}," ({ ok: ",[411,3563,1018],{"class":500},[411,3565,1746],{"class":424},[411,3567,657],{"class":417},[411,3569,530],{"class":417},[411,3571,3572],{"class":424},")\n",[411,3574,3575,3578,3580,3582,3584,3587,3589,3591,3593],{"class":413,"line":517},[411,3576,3577],{"class":417},"            :",[411,3579,3561],{"class":424},[411,3581,973],{"class":500},[411,3583,2806],{"class":424},[411,3585,3586],{"class":461},"'listId is required'",[411,3588,1746],{"class":424},[411,3590,657],{"class":417},[411,3592,530],{"class":417},[411,3594,634],{"class":424},[411,3596,3597],{"class":413,"line":524},[411,3598,743],{"class":424},[411,3600,3601],{"class":413,"line":555},[411,3602,472],{"emptyLinePlaceholder":471},[411,3604,3605,3607,3610,3612,3614,3616,3619,3621,3623,3625,3627,3630],{"class":413,"line":582},[411,3606,754],{"class":417},[411,3608,3609],{"class":558}," fetchPage",[411,3611,562],{"class":424},[411,3613,565],{"class":493},[411,3615,497],{"class":417},[411,3617,3618],{"class":481}," PluginImportProviderInput",[411,3620,573],{"class":424},[411,3622,497],{"class":417},[411,3624,826],{"class":481},[411,3626,541],{"class":424},[411,3628,3629],{"class":481},"PluginImportPageResult",[411,3631,834],{"class":424},[411,3633,3634],{"class":413,"line":617},[411,3635,3636],{"class":520},"        \u002F\u002F `cursor` is `''` on the first page; return `null` to end the walk.\n",[411,3638,3639,3641,3644,3646,3649,3651,3653,3656,3659,3662,3665],{"class":413,"line":637},[411,3640,646],{"class":417},[411,3642,3643],{"class":500}," page",[411,3645,651],{"class":417},[411,3647,3648],{"class":424}," input.cursor ",[411,3650,608],{"class":417},[411,3652,1036],{"class":461},[411,3654,3655],{"class":417}," ?",[411,3657,3658],{"class":500}," 1",[411,3660,3661],{"class":417}," :",[411,3663,3664],{"class":558}," Number",[411,3666,3667],{"class":424},"(input.cursor);\n",[411,3669,3670,3672],{"class":413,"line":643},[411,3671,734],{"class":417},[411,3673,425],{"class":424},[411,3675,3676,3679,3682,3685,3688,3691,3694],{"class":413,"line":674},[411,3677,3678],{"class":424},"            rows: [{ email: ",[411,3680,3681],{"class":461},"`contact-${",[411,3683,3684],{"class":424},"page",[411,3686,3687],{"class":461},"}@example.com`",[411,3689,3690],{"class":424},", fields: { source: ",[411,3692,3693],{"class":461},"'vendor'",[411,3695,3696],{"class":424}," } }],\n",[411,3698,3699,3702,3705,3708,3710,3712,3714,3717,3720,3723,3725],{"class":413,"line":710},[411,3700,3701],{"class":424},"            nextCursor: page ",[411,3703,3704],{"class":417},">=",[411,3706,3707],{"class":500}," 2",[411,3709,3655],{"class":417},[411,3711,611],{"class":500},[411,3713,3661],{"class":417},[411,3715,3716],{"class":558}," String",[411,3718,3719],{"class":424},"(page ",[411,3721,3722],{"class":417},"+",[411,3724,3658],{"class":500},[411,3726,3727],{"class":424},"),\n",[411,3729,3730],{"class":413,"line":726},[411,3731,3732],{"class":424},"        };\n",[411,3734,3735],{"class":413,"line":731},[411,3736,743],{"class":424},[411,3738,3739],{"class":413,"line":740},[411,3740,1049],{"class":424},[3371,3742,3744],{"title":3743,"type":3374},"Noch erreicht kein Import-Lauf einen Plugin-Provider",[11,3745,3746,3747,3750,3751,3753,3754,3756],{},"Die generierte Modul-Registry für Import-Provider existiert, aber es wird keine Naht zur Start-Autorisierung ausgeliefert: Der Import-Walker dispatcht über eine ausschließlich kern-basierte ",[20,3748,3749],{},"INTEGRATION_IMPORT_PROVIDERS","-Map, und ",[20,3752,347],{}," ist eine Union aus zwei Literalen, die ",[20,3755,51],{}," nicht aufnehmen kann. Ein Import-Lauf kann einen beigetragenen Provider heute daher nie erreichen.",[54,3758,3759],{"id":192},"Crons",[384,3761,3764],{"className":3762,"code":3763,"language":389,"meta":390},[387],"crons: [{ id, label, module: { exportPath }, schedule: { intervalMinutes }, timeoutMs }]\n",[20,3765,3763],{"__ignoreMap":390},[11,3767,3768],{},"Scheduling-Limits, durchgesetzt bei der Manifest-Validierung, in der Codegen und bei der Registrierung:",[67,3770,3771,3780],{},[70,3772,3773],{},[73,3774,3775,3777],{},[76,3776,1921],{},[76,3778,3779],{},"Wert",[89,3781,3782,3792],{},[73,3783,3784,3789],{},[94,3785,3786],{},[20,3787,3788],{},"schedule.intervalMinutes",[94,3790,3791],{},"15 … 40 320 (vier Wochen)",[73,3793,3794,3799],{},[94,3795,3796],{},[20,3797,3798],{},"timeoutMs",[94,3800,3801],{},"1 000 … 300 000 (fünf Minuten)",[11,3803,3804,3805,3808,3809,899],{},"Ein Plugin kann Hintergrundarbeit hinzufügen, aber nie eine Hot Loop oder einen faktisch nie laufenden Cron. Der registrierte Convex-Cron-Name ist die namensraumgebundene Art, Registrierungen sind also eindeutig. Jede Ausführung erhält ",[20,3806,3807],{},"{ signal, logger, llm }"," — keinen Convex-Context, keine Tenant-ID, kein Credential — und der Abbruch erfolgt kooperativ über ",[20,3810,3811],{},"signal",[54,3813,3815],{"id":3814},"navigations-und-einstellungseinträge","Navigations- und Einstellungseinträge",[384,3817,3820],{"className":3818,"code":3819,"language":389,"meta":390},[387],"navItems: [{ id, section, name, href, icon, order? }]\nsettingsPanels: [{ id, name, href, icon, order? }]\n",[20,3821,3819],{"__ignoreMap":390},[11,3823,3824,3825,3827],{},"Beide sind reine Daten: ein beschrifteter Link auf einen internen Dashboard-Pfad. Das Label wird auf 64 UTF-16-Code-Units beschnitten (ein astrales Zeichen zählt doppelt, sodass der Manifest-Validator und die renderseitige Beschneidung sich über das Budget einig sind), wobei Steuer- und Bidi-Formatzeichen beim Ableiten des Eintrags entfernt werden — das ist Spoofing-Abwehr, damit ein Plugin kein Label zeichnen kann, das ein Kern-Label optisch imitiert; die XSS-Abwehr ist das HTML-Escaping in Vue. Der Eintrag hängt am Plugin-Flag und wird deterministisch ",[15,3826,2980],{}," jedem Kern-Eintrag einsortiert.",[11,3829,3830,3831,3834],{},"Die Registry dedupliziert nach Ziel-",[20,3832,3833],{},"href",", wobei die erste Registrierung gewinnt und der Kern immer zuerst registriert wird — genau das verhindert, dass ein Plugin ein Kern-Ziel überdeckt. Ein Nav-Eintrag, der auf eine unbekannte oder per Feature abgeschaltete Section zeigt, wird verworfen; ein Plugin kann keine neue Top-Level-Section anlegen.",[11,3836,3837,3840,3841,3843,3844,3847],{},[15,3838,3839],{},"Ein Plugin kann keine Seite ausliefern."," Zur Laufzeit wird kein beliebiger Browser-Code geladen, und die Codegen erzeugt keine Nuxt-Routen — ",[20,3842,3833],{}," muss also auf eine Route auflösen, die der Dashboard-Build bereits hat, sonst wird der Link gerendert und läuft dann in ein 404. Das Ziel, das jedes Plugin geschenkt bekommt, ist seine eigene schema-gerenderte Einstellungsseite unter ",[20,3845,3846],{},"\u002Fdashboard\u002Fadmin\u002Finstance\u002Fplugins\u002F\u003CpluginId>",", auf die beide Referenzmanifeste verlinken. Alles andere muss eine Kern-Route sein oder eine Route, die der Build des Betreibers selbst bereitstellt.",[54,3849,3851],{"id":3850},"settings-schema","Settings-Schema",[11,3853,3854,3856],{},[20,3855,1245],{}," ist kein Contribution-Bucket — es ist ein deklaratives Formular auf oberster Ebene, das der Host rendert, validiert, persistiert und schwärzt, sodass ein Plugin keinen eigenen Client-Code braucht.",[67,3858,3859,3869],{},[70,3860,3861],{},[73,3862,3863,3866],{},[76,3864,3865],{},"Feldart",[76,3867,3868],{},"Zusätzliche Felder",[89,3870,3871,3885,3899,3915,3925],{},[73,3872,3873,3877],{},[94,3874,3875],{},[20,3876,1258],{},[94,3878,3879,355,3882],{},[20,3880,3881],{},"default?",[20,3883,3884],{},"maxLength?",[73,3886,3887,3891],{},[94,3888,3889],{},[20,3890,1261],{},[94,3892,3893,3895,3896,3898],{},[20,3894,1281],{}," (erforderlich, ",[20,3897,1132],{},"-Präfix) — nur Deklaration, siehe unten",[73,3900,3901,3905],{},[94,3902,3903],{},[20,3904,1264],{},[94,3906,3907,355,3909,355,3912],{},[20,3908,3881],{},[20,3910,3911],{},"min?",[20,3913,3914],{},"max?",[73,3916,3917,3921],{},[94,3918,3919],{},[20,3920,1267],{},[94,3922,3923],{},[20,3924,3881],{},[73,3926,3927,3931],{},[94,3928,3929],{},[20,3930,1270],{},[94,3932,3933,355,3936],{},[20,3934,3935],{},"options: [{ value, label }]",[20,3937,3881],{},[11,3939,3940,3941,355,3944,355,3947,355,3950,3953,3954,355,3957,359,3960,3963],{},"Alle Arten tragen ",[20,3942,3943],{},"key",[20,3945,3946],{},"label",[20,3948,3949],{},"description?",[20,3951,3952],{},"required?",". Obergrenzen: 64 Felder, 64 Optionen je Select, 8 192 Zeichen je Textwert. ",[20,3955,3956],{},"__proto__",[20,3958,3959],{},"constructor",[20,3961,3962],{},"prototype"," werden als Keys abgelehnt.",[11,3965,3966,3972,3973,3975,3976,3978],{},[15,3967,3968,3969,3971],{},"Ein ",[20,3970,1261],{},"-Feld speichert nichts."," Es benennt eine Deployment-Umgebungsvariable mit ",[20,3974,1132],{},"-Präfix, und der Host meldet nur, ob diese Variable vorhanden ist; ein Schreibvorgang für einen Secret-Key wird rundweg abgelehnt. Owlat hält damit überhaupt keinen Plugin-Credential-Klartext — es gibt keine Zeile, die leaken, keinen Envelope, der rotiert werden, und keinen Schlüssel, der kompromittiert werden könnte. Nichts anderes wäre sicher zu bauen: Kein Host-Pfad übergibt einem Plugin jemals seine Einstellungen (Plugins erhalten ausschließlich host-vermittelte Services), ein persistiertes Credential wäre also Write-only-Storage. Nutzen Sie ",[20,3977,1182],{},", wenn das Plugin ohne die Variable überhaupt nicht laufen darf.",[54,3980,3982],{"id":3981},"reservierte-namen","Reservierte Namen",[11,3984,3985,3988,3989,355,3992,355,3995,355,3998,355,4001,355,4004,355,4007,359,4010,4013,4014,4017],{},[20,3986,3987],{},"PLUGIN_CONTRIBUTION_KINDS"," enthält außerdem ",[20,3990,3991],{},"lifecycleEffects",[20,3993,3994],{},"assistantTools",[20,3996,3997],{},"inboundAdapters",[20,3999,4000],{},"emailBlocks",[20,4002,4003],{},"commands",[20,4005,4006],{},"panels",[20,4008,4009],{},"widgets",[20,4011,4012],{},"taskCards",". Diese Buckets sind im Manifest-Typ reserviert und werden vom Validator als opake Arrays akzeptiert, aber ",[15,4015,4016],{},"noch verarbeitet sie weder eine Codegen- noch eine Host-Naht"," — die entsprechenden Kern-Registries existieren und stehen ausschließlich Kern-Modulen offen. Einen davon zu deklarieren hat heute keine Laufzeitwirkung. Behandeln Sie sie als reservierte Namen, nicht als Erweiterungspunkte.",[11,4019,4020,4021,4024,4025,4027,4028,4030,4031,4033,4034,4037],{},"Eine Reservierung ist nur so lange kostenlos, wie sie etwas Reales benennt — sie kann also zurückgezogen werden. ",[20,4022,4023],{},"channelAdapters"," wurde es: Die bidirektionale Channel-Adapter-Schnittstelle, auf die er zeigte, ist verschwunden (ihre beiden faked Implementierungen gelöscht, ihre drei funktionierenden neben die einzige Action verschoben, die sie dispatchte), und die Nähte, die sie ersetzt haben — ",[20,4026,98],{}," für ausgehend und ",[20,4029,3997],{}," für eingehend —, haben bereits eigene Buckets. Ein Manifest, das heute ",[20,4032,4023],{}," deklariert, wird mit ",[20,4035,4036],{},"unknown_field"," abgelehnt, genau wie ein Tippfehler. Nichts spricht dagegen, dass der Name zurückkehrt, sobald es wieder eine Channel-Naht gibt.",[4039,4040,4041],"style",{},"html pre.shiki code .s7YZ4, html code.shiki .s7YZ4{--shiki-default:#D73A49;--shiki-dark:#F47067}html pre.shiki code .sYgZi, html code.shiki .sYgZi{--shiki-default:#24292E;--shiki-dark:#ADBAC7}html pre.shiki code .s-HuK, html code.shiki .s-HuK{--shiki-default:#032F62;--shiki-dark:#96D0FF}html pre.shiki code .sOLd2, html code.shiki .sOLd2{--shiki-default:#6F42C1;--shiki-dark:#F69D50}html pre.shiki code .stnAF, html code.shiki .stnAF{--shiki-default:#E36209;--shiki-dark:#F69D50}html pre.shiki code .sviXB, html code.shiki .sviXB{--shiki-default:#005CC5;--shiki-dark:#6CB6FF}html pre.shiki code .sDN9O, html code.shiki .sDN9O{--shiki-default:#6A737D;--shiki-dark:#768390}html pre.shiki code .sPO5f, html code.shiki .sPO5f{--shiki-default:#6F42C1;--shiki-dark:#DCBDFB}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":390,"searchDepth":428,"depth":428,"links":4043},[4044,4048,4055,4056,4057,4059,4060,4061,4062,4063,4064,4065],{"id":56,"depth":428,"text":57,"children":4045},[4046,4047],{"id":61,"depth":434,"text":62},{"id":239,"depth":434,"text":240},{"id":381,"depth":428,"text":382,"children":4049},[4050,4051,4052,4053,4054],{"id":1097,"depth":434,"text":1098},{"id":1235,"depth":434,"text":1236},{"id":1302,"depth":434,"text":1303},{"id":1459,"depth":434,"text":1460},{"id":1970,"depth":434,"text":1971},{"id":2637,"depth":428,"text":2638},{"id":2933,"depth":428,"text":2934},{"id":2965,"depth":428,"text":4058},"Autonomy-Gates (sendGates)",{"id":2998,"depth":428,"text":2999},{"id":3388,"depth":428,"text":3389},{"id":3423,"depth":428,"text":3424},{"id":192,"depth":428,"text":3759},{"id":3814,"depth":428,"text":3815},{"id":3850,"depth":428,"text":3851},{"id":3981,"depth":428,"text":3982},"Jeder Contribution-Bucket, den ein Plugin-Manifest deklarieren kann, seine Capability, sein Modulvertrag und die Host-Semantik darum herum.","md",{},"\u002Fdeveloper\u002Fplugin-contributions",{"title":6,"description":4066},"3.developer\u002F42.plugin-contributions","Uo1mgh4Vt7stNf8gkRWUanpCz5IBAfvGIoN2V217CFM",[4074,4078],{"title":4075,"path":4076,"stem":4077,"children":-1},"Ein Plugin bauen","\u002Fdeveloper\u002Fplugin-authoring","3.developer\u002F41.plugin-authoring",{"title":4079,"path":371,"stem":4080,"children":-1},"Capabilities, Grants & Vertrauen","3.developer\u002F43.plugin-capabilities",1786915109263]