@aglyn/plugins-marketplace 1.0.0-beta.253 → 1.0.0-beta.255

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/model/update-state.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { InstallableArtifactType as MarketplaceArtifactType } from '@aglyn/aglyn/app-utils/artifact-provenance'\nimport { resolveProvenance } from '@aglyn/aglyn/app-utils/artifact-provenance'\nimport {\n offeredPluginVersion,\n type PluginRevocation,\n} from '@aglyn/aglyn/app-utils/plugin-manifest'\n\n/**\n * \"Is what I have installed still what the publisher ships?\" (AGL-1016).\n *\n * This comparison was previously derived inline on the installed-plugins card\n * and nowhere else, so the Plugins index, the installation page and the\n * marketplace listing could each show a different answer — or none. It is\n * exactly the sort of thing that gets re-derived slightly differently in four\n * places, so it lives here, pure, and every surface asks it.\n */\n\nexport type UpdateState =\n /** Running the newest version the publisher offers. */\n | 'current'\n /** A newer version exists and can be taken. */\n | 'update-available'\n /**\n * Installed version is NEWER than what is offered. Not a bug: a publisher\n * installs their own unapproved version to test it, and a version can be\n * withdrawn after someone installed it.\n */\n | 'ahead'\n /** Not enough is known to say — no provenance, or nothing published to compare. */\n | 'unknown'\n\nexport interface UpdateStatus {\n state: UpdateState\n /** The version running, or null when provenance cannot say. */\n installedVersion: string | null\n /** The newest version on offer — for plugins, the newest APPROVED one. */\n availableVersion: string | null\n /**\n * Why the answer is `unknown`, for a UI that should say which kind of\n * silence this is rather than implying the artifact is current.\n */\n unknownReason?: 'no-provenance' | 'nothing-published' | 'incomparable'\n}\n\n/**\n * Orders two artifact versions, or returns null when they cannot be ordered.\n *\n * Two numbering schemes are in play and both are real: copied artifacts get a\n * monotonic integer from the publish route, plugins get the semver string off\n * their manifest. A single string compare handles neither (\"10\" < \"9\",\n * \"1.10.0\" < \"1.9.0\"), so both are parsed as dotted numbers — which covers the\n * integer case as a one-segment version.\n *\n * Anything non-numeric (a prerelease tag, a date-stamped build) is not ordered\n * by guesswork: unequal-and-incomparable is reported as such and surfaces as\n * `unknown`, which is honest, where a string compare would confidently point\n * an update button at an older build.\n */\nexport function compareArtifactVersions(\n a: string | number | null | undefined,\n b: string | number | null | undefined,\n): -1 | 0 | 1 | null {\n if (a == null || b == null || a === '' || b === '') return null\n const left = String(a)\n const right = String(b)\n if (left === right) return 0\n const parse = (value: string): number[] | null => {\n const parts = value.split('.')\n const numbers: number[] = []\n for (const part of parts) {\n if (!/^\\d+$/.test(part)) return null\n numbers.push(Number(part))\n }\n return numbers.length ? numbers : null\n }\n const leftParts = parse(left)\n const rightParts = parse(right)\n if (!leftParts || !rightParts) return null\n const length = Math.max(leftParts.length, rightParts.length)\n for (let index = 0; index < length; index += 1) {\n const leftPart = leftParts[index] ?? 0\n const rightPart = rightParts[index] ?? 0\n if (leftPart < rightPart) return -1\n if (leftPart > rightPart) return 1\n }\n // Equal numerically but not as strings — \"1.0\" and \"1.0.0\" are the same\n // version written two ways.\n return 0\n}\n\n/** The installed side: a plugin pin, or any copied artifact's document. */\nexport interface UpdateComparableInstall {\n version?: unknown\n installedFrom?: Record<string, unknown> | null\n marketplace?: { listingId?: string; version?: unknown } | null\n source?: { listingId?: string; version?: unknown } | null\n listingId?: string\n pluginId?: string\n sha256?: string\n}\n\n/** The listing side, as the public listing document carries it. */\nexport interface UpdateComparableListing {\n artifactType?: string\n type?: string\n kind?: string\n latestVersion?: unknown\n /**\n * The newest version that PASSED REVIEW (AGL-966), denormalised onto the\n * listing by the approval route because `pluginVersions` is server-only.\n */\n latestApprovedVersion?: unknown\n}\n\nconst UNKNOWN: UpdateStatus = {\n state: 'unknown',\n installedVersion: null,\n availableVersion: null,\n unknownReason: 'no-provenance',\n}\n\n/**\n * Compares what is installed against what the listing offers (AGL-1016).\n *\n * For plugins the offer is the newest INSTALLABLE version, never\n * `latestVersion`. Installs already resolve it that way; advertising\n * `latestVersion` would leak AGL-966's guarantee straight back out through a\n * badge, telling a workspace an update exists that the install route would\n * then refuse to give them.\n *\n * `revocation` is the same leak one state over (AGL-2368). Approval is a\n * review verdict and the kill switch does not clear it, so `latestApprovedVersion`\n * could name a stopped version — an \"Update to vX\" for bytes `install-plugin`\n * answers 409 to. Optional because it is a second document and not every\n * caller holds it; every writer of the mirror derives it from\n * `newestInstallableVersion` since AGL-2306, so a caller without one is\n * reading a cache that is correct except in the window between two writes.\n * A caller that HAS it should pass it.\n */\nexport function resolveUpdateState(\n installed: UpdateComparableInstall | null | undefined,\n listing: UpdateComparableListing | null | undefined,\n artifactType?: MarketplaceArtifactType,\n revocation?: PluginRevocation | null,\n): UpdateStatus {\n const provenance = resolveProvenance(installed as never, artifactType)\n if (!installed || provenance.state === 'unknown' || !provenance.version) {\n return UNKNOWN\n }\n const installedVersion = provenance.version\n const type = provenance.artifactType ?? artifactType ?? null\n const available =\n type === 'plugin'\n ? offeredPluginVersion(listing, revocation)\n : listing?.latestVersion\n if (available == null || available === '') {\n return {\n state: 'unknown',\n installedVersion,\n availableVersion: null,\n unknownReason: 'nothing-published',\n }\n }\n const availableVersion = String(available)\n const order = compareArtifactVersions(installedVersion, availableVersion)\n if (order === null) {\n return {\n state: 'unknown',\n installedVersion,\n availableVersion,\n unknownReason: 'incomparable',\n }\n }\n return {\n state: order === 0 ? 'current' : order < 0 ? 'update-available' : 'ahead',\n installedVersion,\n availableVersion,\n }\n}\n\n/**\n * One sentence describing an update state, so four surfaces do not each invent\n * their own wording for the same fact.\n */\nexport function updateStateLabel(status: UpdateStatus): string {\n switch (status.state) {\n case 'update-available':\n return `You have v${status.installedVersion} · v${status.availableVersion} available`\n case 'current':\n return `Up to date · v${status.installedVersion}`\n case 'ahead':\n return `You have v${status.installedVersion}, newer than the published v${status.availableVersion}`\n default:\n return status.unknownReason === 'nothing-published'\n ? 'No published version to compare against'\n : status.unknownReason === 'incomparable'\n ? `You have v${status.installedVersion}; v${status.availableVersion} cannot be ordered against it`\n : 'Installed before update tracking — version unknown'\n }\n}\n"],"names":["resolveProvenance","offeredPluginVersion","compareArtifactVersions","a","b","left","String","right","parse","value","parts","split","numbers","part","test","push","Number","length","leftParts","rightParts","Math","max","index","leftPart","rightPart","UNKNOWN","state","installedVersion","availableVersion","unknownReason","resolveUpdateState","installed","listing","artifactType","revocation","provenance","version","type","available","latestVersion","order","updateStateLabel","status"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/model/update-state.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { InstallableArtifactType as MarketplaceArtifactType } from '@aglyn/aglyn/app-utils/artifact-provenance'\nimport { resolveProvenance } from '@aglyn/aglyn/app-utils/artifact-provenance'\nimport {\n offeredPluginVersion,\n type PluginRevocation,\n} from '@aglyn/aglyn/app-utils/plugin-manifest'\n\nexport {\n compareArtifactVersions,\n type UpdateState,\n type UpdateStatus,\n updateStateLabel,\n} from './marketplace-catalog'\nimport { compareArtifactVersions, type UpdateStatus } from './marketplace-catalog'\n\n/**\n * \"Is what I have installed still what the publisher ships?\" (AGL-1016).\n *\n * This comparison was previously derived inline on the installed-plugins card\n * and nowhere else, so the Plugins index, the installation page and the\n * marketplace listing could each show a different answer — or none. It is\n * exactly the sort of thing that gets re-derived slightly differently in four\n * places, so it lives here, pure, and every surface asks it.\n */\n\n/** The installed side: a plugin pin, or any copied artifact's document. */\nexport interface UpdateComparableInstall {\n version?: unknown\n installedFrom?: Record<string, unknown> | null\n marketplace?: { listingId?: string; version?: unknown } | null\n source?: { listingId?: string; version?: unknown } | null\n listingId?: string\n pluginId?: string\n sha256?: string\n}\n\n/** The listing side, as the public listing document carries it. */\nexport interface UpdateComparableListing {\n artifactType?: string\n type?: string\n kind?: string\n latestVersion?: unknown\n /**\n * The newest version that PASSED REVIEW (AGL-966), denormalised onto the\n * listing by the approval route because `pluginVersions` is server-only.\n */\n latestApprovedVersion?: unknown\n}\n\nconst UNKNOWN: UpdateStatus = {\n state: 'unknown',\n installedVersion: null,\n availableVersion: null,\n unknownReason: 'no-provenance',\n}\n\n/**\n * Compares what is installed against what the listing offers (AGL-1016).\n *\n * For plugins the offer is the newest INSTALLABLE version, never\n * `latestVersion`. Installs already resolve it that way; advertising\n * `latestVersion` would leak AGL-966's guarantee straight back out through a\n * badge, telling a workspace an update exists that the install route would\n * then refuse to give them.\n *\n * `revocation` is the same leak one state over (AGL-2368). Approval is a\n * review verdict and the kill switch does not clear it, so `latestApprovedVersion`\n * could name a stopped version — an \"Update to vX\" for bytes `install-plugin`\n * answers 409 to. Optional because it is a second document and not every\n * caller holds it; every writer of the mirror derives it from\n * `newestInstallableVersion` since AGL-2306, so a caller without one is\n * reading a cache that is correct except in the window between two writes.\n * A caller that HAS it should pass it.\n */\nexport function resolveUpdateState(\n installed: UpdateComparableInstall | null | undefined,\n listing: UpdateComparableListing | null | undefined,\n artifactType?: MarketplaceArtifactType,\n revocation?: PluginRevocation | null,\n): UpdateStatus {\n const provenance = resolveProvenance(installed as never, artifactType)\n if (!installed || provenance.state === 'unknown' || !provenance.version) {\n return UNKNOWN\n }\n const installedVersion = provenance.version\n const type = provenance.artifactType ?? artifactType ?? null\n const available =\n type === 'plugin'\n ? offeredPluginVersion(listing, revocation)\n : listing?.latestVersion\n if (available == null || available === '') {\n return {\n state: 'unknown',\n installedVersion,\n availableVersion: null,\n unknownReason: 'nothing-published',\n }\n }\n const availableVersion = String(available)\n const order = compareArtifactVersions(installedVersion, availableVersion)\n if (order === null) {\n return {\n state: 'unknown',\n installedVersion,\n availableVersion,\n unknownReason: 'incomparable',\n }\n }\n return {\n state: order === 0 ? 'current' : order < 0 ? 'update-available' : 'ahead',\n installedVersion,\n availableVersion,\n }\n}\n\n"],"names":["resolveProvenance","offeredPluginVersion","compareArtifactVersions","updateStateLabel","UNKNOWN","state","installedVersion","availableVersion","unknownReason","resolveUpdateState","installed","listing","artifactType","revocation","provenance","version","type","available","latestVersion","String","order"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,iBAAiB,QAAQ,6CAA4C;AAC9E,SACEC,oBAAoB,QAEf,yCAAwC;AAE/C,SACEC,uBAAuB,EAGvBC,gBAAgB,QACX,2BAAuB;AAC9B,SAASD,uBAAuB,QAA2B,2BAAuB;AAoClF,MAAME,UAAwB;IAC5BC,OAAO;IACPC,kBAAkB;IAClBC,kBAAkB;IAClBC,eAAe;AACjB;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASC,mBACdC,SAAqD,EACrDC,OAAmD,EACnDC,YAAsC,EACtCC,UAAoC;QAOvBC,MAAAA;IALb,MAAMA,aAAad,kBAAkBU,WAAoBE;IACzD,IAAI,CAACF,aAAaI,WAAWT,KAAK,KAAK,aAAa,CAACS,WAAWC,OAAO,EAAE;QACvE,OAAOX;IACT;IACA,MAAME,mBAAmBQ,WAAWC,OAAO;IAC3C,MAAMC,QAAOF,QAAAA,2BAAAA,WAAWF,YAAY,YAAvBE,2BAA2BF,wBAA3BE,OAA2C;IACxD,MAAMG,YACJD,SAAS,WACLf,qBAAqBU,SAASE,cAC9BF,2BAAAA,QAASO,aAAa;IAC5B,IAAID,aAAa,QAAQA,cAAc,IAAI;QACzC,OAAO;YACLZ,OAAO;YACPC;YACAC,kBAAkB;YAClBC,eAAe;QACjB;IACF;IACA,MAAMD,mBAAmBY,OAAOF;IAChC,MAAMG,QAAQlB,wBAAwBI,kBAAkBC;IACxD,IAAIa,UAAU,MAAM;QAClB,OAAO;YACLf,OAAO;YACPC;YACAC;YACAC,eAAe;QACjB;IACF;IACA,OAAO;QACLH,OAAOe,UAAU,IAAI,YAAYA,QAAQ,IAAI,qBAAqB;QAClEd;QACAC;IACF;AACF"}