@ixo/editor 6.31.4 → 6.32.1
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.
- package/dist/action-manifest-v2.schema.json +214 -0
- package/dist/action-manifest.json +79 -58
- package/dist/{chunk-2HFSD5YP.js → chunk-5JF23UP3.js} +2 -2
- package/dist/{chunk-PSZOCS5V.js → chunk-A4CWC4AG.js} +2 -2
- package/dist/{chunk-6OMM32CE.js → chunk-NEOPTPDF.js} +436 -44
- package/dist/chunk-NEOPTPDF.js.map +1 -0
- package/dist/{connections-B24zj0RI.d.ts → connections-1NtNQrsY.d.ts} +1 -1
- package/dist/core/index.cjs +443 -43
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +299 -5
- package/dist/core/index.js +14 -2
- package/dist/core/index.js.map +1 -1
- package/dist/{graphql-client-BICFLCX8.d.ts → graphql-client-Bn0tN049.d.ts} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/mantine/index.d.ts +3 -3
- package/dist/mantine/index.js +2 -2
- package/dist/{runtime-DFPayq89.d.ts → runtime-BFwvCQDF.d.ts} +15 -0
- package/package.json +2 -1
- package/dist/chunk-6OMM32CE.js.map +0 -1
- /package/dist/{chunk-2HFSD5YP.js.map → chunk-5JF23UP3.js.map} +0 -0
- /package/dist/{chunk-PSZOCS5V.js.map → chunk-A4CWC4AG.js.map} +0 -0
|
@@ -1094,12 +1094,11 @@ var PRESENTATION = {
|
|
|
1094
1094
|
"qi/topic.action.receipt.record": { displayName: "Record Action Receipt", description: "Record a signed Action receipt against its Topic request" },
|
|
1095
1095
|
"qi/topic.action.request": { displayName: "Request Topic Action", description: "Request an Action against the current Topic revision" },
|
|
1096
1096
|
"qi/topic.context.link": { displayName: "Link Topic Context", description: "Link a referenced resource or service to the Topic" },
|
|
1097
|
-
"qi/topic.contract.
|
|
1097
|
+
"qi/topic.contract.confirm-setup": { displayName: "Confirm Topic Setup", description: "Confirm the exact proposed Topic setup revision" },
|
|
1098
1098
|
"qi/topic.decision.record": { displayName: "Record Topic Decision", description: "Record an authorised decision and its rationale" },
|
|
1099
1099
|
"qi/topic.file.attach-reference": { displayName: "Attach File Reference", description: "Attach a pinned VFS file reference to the Topic" },
|
|
1100
1100
|
"qi/topic.flow.bind": { displayName: "Bind Flow to Topic", description: "Bind a governed Flow revision to the Topic" },
|
|
1101
1101
|
"qi/topic.flow.unbind": { displayName: "Unbind Flow from Topic", description: "Remove an existing Flow binding from the Topic" },
|
|
1102
|
-
"qi/topic.outcome.confirm": { displayName: "Confirm Topic Outcome", description: "Confirm a proposed outcome using the stated authority" },
|
|
1103
1102
|
"qi/topic.outcome.propose": { displayName: "Propose Topic Outcome", description: "Propose an evidence-backed outcome for review" },
|
|
1104
1103
|
"qi/topic.status.transition": { displayName: "Change Topic Status", description: "Move the Topic between permitted lifecycle statuses" },
|
|
1105
1104
|
"qi/wallet.fund": { displayName: "Fund Wallet", description: "Fund a wallet with an on-chain transfer" },
|
|
@@ -1336,7 +1335,11 @@ var ACTION_TYPE_ALIASES = {
|
|
|
1336
1335
|
// qi/ixo.calendar.event.* instead.
|
|
1337
1336
|
"qi/calendar.event.create": "qi/googlecalendar.event.create-self",
|
|
1338
1337
|
"qi/calendar.event.update": "qi/googlecalendar.event.update-self",
|
|
1339
|
-
"qi/calendar.event.list": "qi/googlecalendar.event.list-self"
|
|
1338
|
+
"qi/calendar.event.list": "qi/googlecalendar.event.list-self",
|
|
1339
|
+
// Topic v3 called setup confirmation "accept contract". Persisted Flow
|
|
1340
|
+
// documents keep that action key, so resolve it to the v4 confirmation
|
|
1341
|
+
// contract while new documents use the canonical name.
|
|
1342
|
+
"qi/topic.contract.accept": "qi/topic.contract.confirm-setup"
|
|
1340
1343
|
};
|
|
1341
1344
|
var aliases = new Map(Object.entries(ACTION_TYPE_ALIASES));
|
|
1342
1345
|
function resolveActionType(type) {
|
|
@@ -1601,6 +1604,345 @@ function actionManifestIssues(manifest = generateActionManifest()) {
|
|
|
1601
1604
|
return issues;
|
|
1602
1605
|
}
|
|
1603
1606
|
|
|
1607
|
+
// src/core/lib/actionRegistry/manifestV2.schema.ts
|
|
1608
|
+
var ACTION_MANIFEST_V2_SCHEMA = {
|
|
1609
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1610
|
+
$id: "https://ixo.world/schemas/qi/action-manifest-v2.schema.json",
|
|
1611
|
+
type: "object",
|
|
1612
|
+
additionalProperties: false,
|
|
1613
|
+
required: ["manifestVersion", "manifestId", "generatedAt", "package", "issuer", "compatibility", "actions", "primitives", "integrity"],
|
|
1614
|
+
properties: {
|
|
1615
|
+
manifestVersion: { const: "2.0" },
|
|
1616
|
+
manifestId: { type: "string", minLength: 1 },
|
|
1617
|
+
generatedAt: {
|
|
1618
|
+
type: "string",
|
|
1619
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$"
|
|
1620
|
+
},
|
|
1621
|
+
package: {
|
|
1622
|
+
type: "object",
|
|
1623
|
+
additionalProperties: false,
|
|
1624
|
+
required: ["name", "version", "sourceCommit"],
|
|
1625
|
+
properties: {
|
|
1626
|
+
name: { type: "string", minLength: 1 },
|
|
1627
|
+
version: { type: "string", minLength: 1 },
|
|
1628
|
+
sourceCommit: { type: "string", minLength: 1 },
|
|
1629
|
+
buildId: { type: "string", minLength: 1 },
|
|
1630
|
+
distributionUrl: { type: "string", pattern: "^[a-zA-Z][a-zA-Z0-9+.-]*:" }
|
|
1631
|
+
}
|
|
1632
|
+
},
|
|
1633
|
+
issuer: {
|
|
1634
|
+
type: "object",
|
|
1635
|
+
additionalProperties: false,
|
|
1636
|
+
required: ["did", "verificationMethod"],
|
|
1637
|
+
properties: {
|
|
1638
|
+
did: { type: "string", pattern: "^did:[a-z0-9]+:.+" },
|
|
1639
|
+
verificationMethod: { type: "string", pattern: "^did:[a-z0-9]+:.+#.+" }
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
compatibility: {
|
|
1643
|
+
type: "object",
|
|
1644
|
+
additionalProperties: false,
|
|
1645
|
+
required: ["engine", "flowSchemaVersions", "features"],
|
|
1646
|
+
properties: {
|
|
1647
|
+
engine: {
|
|
1648
|
+
type: "object",
|
|
1649
|
+
additionalProperties: false,
|
|
1650
|
+
required: ["versionRange"],
|
|
1651
|
+
properties: {
|
|
1652
|
+
versionRange: { type: "string", minLength: 1 }
|
|
1653
|
+
}
|
|
1654
|
+
},
|
|
1655
|
+
flowSchemaVersions: {
|
|
1656
|
+
type: "array",
|
|
1657
|
+
minItems: 1,
|
|
1658
|
+
uniqueItems: true,
|
|
1659
|
+
items: { type: "string", minLength: 1 }
|
|
1660
|
+
},
|
|
1661
|
+
features: {
|
|
1662
|
+
type: "array",
|
|
1663
|
+
minItems: 1,
|
|
1664
|
+
uniqueItems: true,
|
|
1665
|
+
items: { type: "string", minLength: 1 }
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
},
|
|
1669
|
+
actions: {
|
|
1670
|
+
type: "array",
|
|
1671
|
+
items: { $ref: "#/$defs/contract" }
|
|
1672
|
+
},
|
|
1673
|
+
primitives: {
|
|
1674
|
+
type: "array",
|
|
1675
|
+
items: { $ref: "#/$defs/contract" }
|
|
1676
|
+
},
|
|
1677
|
+
integrity: {
|
|
1678
|
+
type: "object",
|
|
1679
|
+
additionalProperties: false,
|
|
1680
|
+
required: ["canonicalization", "digest", "signature"],
|
|
1681
|
+
properties: {
|
|
1682
|
+
canonicalization: { const: "RFC8785" },
|
|
1683
|
+
digest: {
|
|
1684
|
+
type: "object",
|
|
1685
|
+
additionalProperties: false,
|
|
1686
|
+
required: ["algorithm", "value"],
|
|
1687
|
+
properties: {
|
|
1688
|
+
algorithm: { const: "SHA-256" },
|
|
1689
|
+
value: { type: "string", pattern: "^sha256:[0-9a-f]{64}$" }
|
|
1690
|
+
}
|
|
1691
|
+
},
|
|
1692
|
+
signature: {
|
|
1693
|
+
type: "object",
|
|
1694
|
+
additionalProperties: false,
|
|
1695
|
+
required: ["algorithm", "verificationMethod", "value"],
|
|
1696
|
+
properties: {
|
|
1697
|
+
algorithm: { type: "string", minLength: 1 },
|
|
1698
|
+
verificationMethod: { type: "string", pattern: "^did:[a-z0-9]+:.+#.+" },
|
|
1699
|
+
value: { type: "string", minLength: 1 }
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
},
|
|
1705
|
+
$defs: {
|
|
1706
|
+
contract: {
|
|
1707
|
+
type: "object",
|
|
1708
|
+
required: ["type", "contractVersion"],
|
|
1709
|
+
properties: {
|
|
1710
|
+
type: { type: "string", minLength: 1 },
|
|
1711
|
+
contractVersion: { type: "string", minLength: 1 },
|
|
1712
|
+
aliases: {
|
|
1713
|
+
type: "array",
|
|
1714
|
+
uniqueItems: true,
|
|
1715
|
+
items: { type: "string", minLength: 1 }
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
};
|
|
1721
|
+
|
|
1722
|
+
// src/core/lib/actionRegistry/manifestV2.ts
|
|
1723
|
+
import Ajv20202 from "ajv/dist/2020.js";
|
|
1724
|
+
var ActionManifestV2VerificationError = class extends Error {
|
|
1725
|
+
constructor(code, message) {
|
|
1726
|
+
super(message);
|
|
1727
|
+
this.name = "ActionManifestV2VerificationError";
|
|
1728
|
+
this.code = code;
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
var validateSignedManifest = new Ajv20202({ allErrors: true, strict: false }).compile(ACTION_MANIFEST_V2_SCHEMA);
|
|
1732
|
+
var SIGNATURE_DOMAIN = "qi.action-manifest.v2\0";
|
|
1733
|
+
function isPlainObject(value) {
|
|
1734
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1735
|
+
return prototype === Object.prototype || prototype === null;
|
|
1736
|
+
}
|
|
1737
|
+
function assertValidUnicode(value) {
|
|
1738
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
1739
|
+
const codeUnit = value.charCodeAt(index);
|
|
1740
|
+
if (codeUnit >= 55296 && codeUnit <= 56319) {
|
|
1741
|
+
const next = value.charCodeAt(index + 1);
|
|
1742
|
+
if (!(next >= 56320 && next <= 57343)) {
|
|
1743
|
+
throw new TypeError("Manifest v2 contains an unpaired Unicode surrogate");
|
|
1744
|
+
}
|
|
1745
|
+
index += 1;
|
|
1746
|
+
} else if (codeUnit >= 56320 && codeUnit <= 57343) {
|
|
1747
|
+
throw new TypeError("Manifest v2 contains an unpaired Unicode surrogate");
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
function canonicalizeManifestV2Payload(payload) {
|
|
1752
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
1753
|
+
const serialize = (value) => {
|
|
1754
|
+
if (value === null || typeof value === "boolean") {
|
|
1755
|
+
return JSON.stringify(value);
|
|
1756
|
+
}
|
|
1757
|
+
if (typeof value === "string") {
|
|
1758
|
+
assertValidUnicode(value);
|
|
1759
|
+
return JSON.stringify(value);
|
|
1760
|
+
}
|
|
1761
|
+
if (typeof value === "number") {
|
|
1762
|
+
if (!Number.isFinite(value)) {
|
|
1763
|
+
throw new TypeError("Manifest v2 contains a non-finite number");
|
|
1764
|
+
}
|
|
1765
|
+
return JSON.stringify(value);
|
|
1766
|
+
}
|
|
1767
|
+
if (typeof value !== "object") {
|
|
1768
|
+
throw new TypeError(`Manifest v2 contains a non-JSON value: ${typeof value}`);
|
|
1769
|
+
}
|
|
1770
|
+
if (ancestors.has(value)) {
|
|
1771
|
+
throw new TypeError("Manifest v2 contains a circular reference");
|
|
1772
|
+
}
|
|
1773
|
+
ancestors.add(value);
|
|
1774
|
+
try {
|
|
1775
|
+
if (Array.isArray(value)) {
|
|
1776
|
+
return `[${value.map((entry) => serialize(entry)).join(",")}]`;
|
|
1777
|
+
}
|
|
1778
|
+
if (!isPlainObject(value)) {
|
|
1779
|
+
throw new TypeError("Manifest v2 contains a non-plain object");
|
|
1780
|
+
}
|
|
1781
|
+
return `{${Object.keys(value).sort().map((key) => {
|
|
1782
|
+
assertValidUnicode(key);
|
|
1783
|
+
return `${JSON.stringify(key)}:${serialize(value[key])}`;
|
|
1784
|
+
}).join(",")}}`;
|
|
1785
|
+
} finally {
|
|
1786
|
+
ancestors.delete(value);
|
|
1787
|
+
}
|
|
1788
|
+
};
|
|
1789
|
+
return serialize(payload);
|
|
1790
|
+
}
|
|
1791
|
+
async function computeActionManifestV2Digest(payload) {
|
|
1792
|
+
if (!globalThis.crypto?.subtle) {
|
|
1793
|
+
throw new Error("Web Crypto is required to digest an Action Manifest v2 contract");
|
|
1794
|
+
}
|
|
1795
|
+
const canonicalPayload = canonicalizeManifestV2Payload(payload);
|
|
1796
|
+
const digest2 = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalPayload));
|
|
1797
|
+
const hex = Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1798
|
+
return `sha256:${hex}`;
|
|
1799
|
+
}
|
|
1800
|
+
function signatureInput(digest2) {
|
|
1801
|
+
return new TextEncoder().encode(`${SIGNATURE_DOMAIN}${digest2}`);
|
|
1802
|
+
}
|
|
1803
|
+
function schemaFailure() {
|
|
1804
|
+
const details = (validateSignedManifest.errors || []).map((error) => `${error.instancePath || "/"} ${error.message || "is invalid"}`).join("; ");
|
|
1805
|
+
return new ActionManifestV2VerificationError("INVALID_MANIFEST", details ? `Action Manifest v2 is invalid: ${details}` : "Action Manifest v2 is invalid");
|
|
1806
|
+
}
|
|
1807
|
+
function payloadFromSignedManifest(manifest) {
|
|
1808
|
+
const { integrity: _integrity, ...payload } = manifest;
|
|
1809
|
+
return payload;
|
|
1810
|
+
}
|
|
1811
|
+
function assertContractIdentities(payload) {
|
|
1812
|
+
const contracts = [...payload.actions, ...payload.primitives];
|
|
1813
|
+
const canonicalTypes = /* @__PURE__ */ new Set();
|
|
1814
|
+
for (const contract of contracts) {
|
|
1815
|
+
if (canonicalTypes.has(contract.type)) {
|
|
1816
|
+
throw new ActionManifestV2VerificationError("DUPLICATE_CONTRACT_TYPE", `Manifest contains duplicate canonical contract type: ${contract.type}`);
|
|
1817
|
+
}
|
|
1818
|
+
canonicalTypes.add(contract.type);
|
|
1819
|
+
}
|
|
1820
|
+
for (const [groupName, group] of [
|
|
1821
|
+
["actions", payload.actions],
|
|
1822
|
+
["primitives", payload.primitives]
|
|
1823
|
+
]) {
|
|
1824
|
+
for (let index = 1; index < group.length; index += 1) {
|
|
1825
|
+
if (group[index - 1].type > group[index].type) {
|
|
1826
|
+
throw new ActionManifestV2VerificationError("UNSORTED_CONTRACTS", `Manifest ${groupName} must be sorted by canonical type`);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
const claimedNames = new Map(Array.from(canonicalTypes, (type) => [type, type]));
|
|
1831
|
+
for (const contract of contracts) {
|
|
1832
|
+
const aliases2 = contract.aliases;
|
|
1833
|
+
if (!Array.isArray(aliases2)) continue;
|
|
1834
|
+
for (const alias of aliases2) {
|
|
1835
|
+
const existingOwner = claimedNames.get(alias);
|
|
1836
|
+
if (existingOwner) {
|
|
1837
|
+
throw new ActionManifestV2VerificationError("AMBIGUOUS_ALIAS", `Manifest alias ${alias} conflicts with contract ${existingOwner}`);
|
|
1838
|
+
}
|
|
1839
|
+
claimedNames.set(alias, contract.type);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
function deepFreeze(value) {
|
|
1844
|
+
for (const child of Object.values(value)) {
|
|
1845
|
+
if (typeof child === "object" && child !== null && !Object.isFrozen(child)) {
|
|
1846
|
+
deepFreeze(child);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
return Object.freeze(value);
|
|
1850
|
+
}
|
|
1851
|
+
async function signActionManifestV2(payload, signer) {
|
|
1852
|
+
if (signer.issuerDid !== payload.issuer.did || signer.verificationMethod !== payload.issuer.verificationMethod) {
|
|
1853
|
+
throw new ActionManifestV2VerificationError("SIGNER_MISMATCH", "The Manifest v2 signer does not match the declared issuer verification method");
|
|
1854
|
+
}
|
|
1855
|
+
assertContractIdentities(payload);
|
|
1856
|
+
let digest2;
|
|
1857
|
+
try {
|
|
1858
|
+
digest2 = await computeActionManifestV2Digest(payload);
|
|
1859
|
+
} catch (error) {
|
|
1860
|
+
throw new ActionManifestV2VerificationError(
|
|
1861
|
+
"INVALID_MANIFEST",
|
|
1862
|
+
error instanceof Error ? `Action Manifest v2 cannot be canonicalized: ${error.message}` : "Action Manifest v2 cannot be canonicalized"
|
|
1863
|
+
);
|
|
1864
|
+
}
|
|
1865
|
+
const signature = await signer.sign(signatureInput(digest2));
|
|
1866
|
+
if (!signature) {
|
|
1867
|
+
throw new ActionManifestV2VerificationError("INVALID_SIGNATURE", "The Manifest v2 signer returned an empty signature");
|
|
1868
|
+
}
|
|
1869
|
+
const signed = {
|
|
1870
|
+
...payload,
|
|
1871
|
+
integrity: {
|
|
1872
|
+
canonicalization: "RFC8785",
|
|
1873
|
+
digest: {
|
|
1874
|
+
algorithm: "SHA-256",
|
|
1875
|
+
value: digest2
|
|
1876
|
+
},
|
|
1877
|
+
signature: {
|
|
1878
|
+
algorithm: signer.algorithm,
|
|
1879
|
+
verificationMethod: signer.verificationMethod,
|
|
1880
|
+
value: signature
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
};
|
|
1884
|
+
if (!validateSignedManifest(signed)) {
|
|
1885
|
+
throw schemaFailure();
|
|
1886
|
+
}
|
|
1887
|
+
assertContractIdentities(payload);
|
|
1888
|
+
return signed;
|
|
1889
|
+
}
|
|
1890
|
+
async function verifyActionManifestV2(candidate, trustPolicy) {
|
|
1891
|
+
if (typeof candidate !== "object" || candidate === null || !("manifestVersion" in candidate) || candidate.manifestVersion !== "2.0") {
|
|
1892
|
+
throw new ActionManifestV2VerificationError("UNSUPPORTED_MANIFEST_VERSION", "Only Action Manifest version 2.0 can cross this execution boundary");
|
|
1893
|
+
}
|
|
1894
|
+
if (!("integrity" in candidate) || typeof candidate.integrity !== "object") {
|
|
1895
|
+
throw new ActionManifestV2VerificationError("UNSIGNED_MANIFEST", "A signature and digest are required to load Action Manifest v2 for execution");
|
|
1896
|
+
}
|
|
1897
|
+
if (!validateSignedManifest(candidate)) {
|
|
1898
|
+
throw schemaFailure();
|
|
1899
|
+
}
|
|
1900
|
+
const manifest = candidate;
|
|
1901
|
+
const { issuer, integrity } = manifest;
|
|
1902
|
+
assertContractIdentities(manifest);
|
|
1903
|
+
if (!trustPolicy.trustedIssuerDids.includes(issuer.did)) {
|
|
1904
|
+
throw new ActionManifestV2VerificationError("UNTRUSTED_ISSUER", `Manifest issuer is not trusted: ${issuer.did}`);
|
|
1905
|
+
}
|
|
1906
|
+
if (trustPolicy.revokedIssuerDids?.includes(issuer.did)) {
|
|
1907
|
+
throw new ActionManifestV2VerificationError("REVOKED_ISSUER", `Manifest issuer is revoked: ${issuer.did}`);
|
|
1908
|
+
}
|
|
1909
|
+
if (integrity.signature.verificationMethod !== issuer.verificationMethod || !integrity.signature.verificationMethod.startsWith(`${issuer.did}#`)) {
|
|
1910
|
+
throw new ActionManifestV2VerificationError("VERIFICATION_METHOD_MISMATCH", "The signature verification method does not belong to the declared manifest issuer");
|
|
1911
|
+
}
|
|
1912
|
+
if (!trustPolicy.allowedSignatureAlgorithms.includes(integrity.signature.algorithm)) {
|
|
1913
|
+
throw new ActionManifestV2VerificationError("DISALLOWED_SIGNATURE_ALGORITHM", `Manifest signature algorithm is not allowed: ${integrity.signature.algorithm}`);
|
|
1914
|
+
}
|
|
1915
|
+
let digest2;
|
|
1916
|
+
try {
|
|
1917
|
+
digest2 = await computeActionManifestV2Digest(payloadFromSignedManifest(manifest));
|
|
1918
|
+
} catch (error) {
|
|
1919
|
+
throw new ActionManifestV2VerificationError(
|
|
1920
|
+
"INVALID_MANIFEST",
|
|
1921
|
+
error instanceof Error ? `Action Manifest v2 cannot be canonicalized: ${error.message}` : "Action Manifest v2 cannot be canonicalized"
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
if (digest2 !== integrity.digest.value) {
|
|
1925
|
+
throw new ActionManifestV2VerificationError("DIGEST_MISMATCH", "Manifest payload does not match its signed digest");
|
|
1926
|
+
}
|
|
1927
|
+
let validSignature = false;
|
|
1928
|
+
try {
|
|
1929
|
+
validSignature = await trustPolicy.verifySignature({
|
|
1930
|
+
issuerDid: issuer.did,
|
|
1931
|
+
verificationMethod: integrity.signature.verificationMethod,
|
|
1932
|
+
algorithm: integrity.signature.algorithm,
|
|
1933
|
+
data: signatureInput(digest2),
|
|
1934
|
+
signature: integrity.signature.value
|
|
1935
|
+
});
|
|
1936
|
+
} catch {
|
|
1937
|
+
validSignature = false;
|
|
1938
|
+
}
|
|
1939
|
+
if (!validSignature) {
|
|
1940
|
+
throw new ActionManifestV2VerificationError("INVALID_SIGNATURE", "Manifest signature verification failed");
|
|
1941
|
+
}
|
|
1942
|
+
const trustedSnapshot = JSON.parse(JSON.stringify(manifest));
|
|
1943
|
+
return deepFreeze(trustedSnapshot);
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1604
1946
|
// src/core/lib/actionRegistry/inputRequirements.ts
|
|
1605
1947
|
function isBlankInputValue(value) {
|
|
1606
1948
|
if (value == null) return true;
|
|
@@ -10498,7 +10840,7 @@ function stripHtml2(s) {
|
|
|
10498
10840
|
}
|
|
10499
10841
|
|
|
10500
10842
|
// src/core/lib/actionRegistry/actions/evalRubric/schemaGate.ts
|
|
10501
|
-
import
|
|
10843
|
+
import Ajv20203 from "ajv/dist/2020.js";
|
|
10502
10844
|
|
|
10503
10845
|
// src/core/lib/actionRegistry/actions/evalRubric/types.ts
|
|
10504
10846
|
var RUBRIC_CTX_TOKENS = [
|
|
@@ -10582,7 +10924,7 @@ async function getValidator(fetchSchema, evalEngineUrl) {
|
|
|
10582
10924
|
if (compiledValidator) return compiledValidator;
|
|
10583
10925
|
const schema = await fetchSchema(evalEngineUrl);
|
|
10584
10926
|
if (!schema || typeof schema !== "object") throw new Error("the rules service returned no schema");
|
|
10585
|
-
const validate = new
|
|
10927
|
+
const validate = new Ajv20203({ allErrors: true, strict: false }).compile(schema);
|
|
10586
10928
|
compiledValidator = validate;
|
|
10587
10929
|
return validate;
|
|
10588
10930
|
}
|
|
@@ -12756,6 +13098,7 @@ registerTopicOperation({
|
|
|
12756
13098
|
executorPreference: { type: "string", enum: ["qi-flow", "qiforge", "mcp"] },
|
|
12757
13099
|
bindingId: { type: "string" },
|
|
12758
13100
|
confirmationPolicy: { type: "string", enum: ["inherit", "required"] },
|
|
13101
|
+
transitionCode: { type: "string" },
|
|
12759
13102
|
idempotencyKey: { type: "string" }
|
|
12760
13103
|
}
|
|
12761
13104
|
},
|
|
@@ -12774,6 +13117,7 @@ registerTopicOperation({
|
|
|
12774
13117
|
const inputDigest = requiredString(inputs.inputDigest, "inputDigest");
|
|
12775
13118
|
const derived = (purpose) => sha256Digest({ purpose, parentRequestId: topic.requestId, topicId: topic.topicId, actionType: target.type, inputDigest });
|
|
12776
13119
|
return {
|
|
13120
|
+
...inputs.transitionCode ? { transitionCode: String(inputs.transitionCode) } : {},
|
|
12777
13121
|
request: {
|
|
12778
13122
|
version: 1,
|
|
12779
13123
|
requestId: String(inputs.requestId || derived("topic-action-request")),
|
|
@@ -12839,9 +13183,15 @@ registerTopicOperation({
|
|
|
12839
13183
|
ability: "topic/change-status",
|
|
12840
13184
|
inputSchema: {
|
|
12841
13185
|
type: "object",
|
|
12842
|
-
required: ["from", "to", "reason"],
|
|
13186
|
+
required: ["from", "to", "transitionCode", "reason"],
|
|
12843
13187
|
additionalProperties: false,
|
|
12844
|
-
properties: {
|
|
13188
|
+
properties: {
|
|
13189
|
+
from: { type: "string" },
|
|
13190
|
+
to: { type: "string" },
|
|
13191
|
+
transitionCode: { type: "string" },
|
|
13192
|
+
reason: { type: "string" },
|
|
13193
|
+
idempotencyKey: { type: "string" }
|
|
13194
|
+
}
|
|
12845
13195
|
},
|
|
12846
13196
|
buildPayload: async (inputs, ctx) => {
|
|
12847
13197
|
const from = requiredString(inputs.from, "from");
|
|
@@ -12854,16 +13204,21 @@ registerTopicOperation({
|
|
|
12854
13204
|
const outcome = projection.outcome;
|
|
12855
13205
|
if (completion?.requiresOutcomeRecord === true && !outcome?.outcomeRecordId) throw new Error("Topic policy requires an accepted outcome record before resolution");
|
|
12856
13206
|
}
|
|
12857
|
-
return {
|
|
13207
|
+
return {
|
|
13208
|
+
from,
|
|
13209
|
+
to,
|
|
13210
|
+
transitionCode: requiredString(inputs.transitionCode, "transitionCode"),
|
|
13211
|
+
reason: requiredString(inputs.reason, "reason")
|
|
13212
|
+
};
|
|
12858
13213
|
}
|
|
12859
13214
|
});
|
|
12860
13215
|
registerTopicOperation({
|
|
12861
|
-
type: "qi/topic.contract.
|
|
12862
|
-
can: "topic/contract.
|
|
12863
|
-
operationType: "
|
|
13216
|
+
type: "qi/topic.contract.confirm-setup",
|
|
13217
|
+
can: "topic/contract.confirm-setup",
|
|
13218
|
+
operationType: "confirm-setup",
|
|
12864
13219
|
confirmation: true,
|
|
12865
13220
|
owner: "human",
|
|
12866
|
-
ability: "topic/
|
|
13221
|
+
ability: "topic/confirm-setup",
|
|
12867
13222
|
inputSchema: {
|
|
12868
13223
|
type: "object",
|
|
12869
13224
|
required: ["contractRevision", "contractDigest", "confirmationReference"],
|
|
@@ -12872,6 +13227,7 @@ registerTopicOperation({
|
|
|
12872
13227
|
contractRevision: { type: "string" },
|
|
12873
13228
|
contractDigest: { type: "string", pattern: "^sha256:" },
|
|
12874
13229
|
confirmationReference: { type: "string" },
|
|
13230
|
+
transitionCode: { type: "string" },
|
|
12875
13231
|
idempotencyKey: { type: "string" }
|
|
12876
13232
|
}
|
|
12877
13233
|
},
|
|
@@ -12879,8 +13235,13 @@ registerTopicOperation({
|
|
|
12879
13235
|
const revision = requiredString(inputs.contractRevision, "contractRevision");
|
|
12880
13236
|
const digest2 = requiredString(inputs.contractDigest, "contractDigest");
|
|
12881
13237
|
if (revision !== topicContext(ctx).contract.revision || digest2 !== topicContext(ctx).contract.digest)
|
|
12882
|
-
throw new Error("
|
|
12883
|
-
return {
|
|
13238
|
+
throw new Error("Setup confirmation must target the exact proposed contract revision and digest");
|
|
13239
|
+
return {
|
|
13240
|
+
contractRevision: revision,
|
|
13241
|
+
contractDigest: digest2,
|
|
13242
|
+
confirmationReference: requiredString(inputs.confirmationReference, "confirmationReference"),
|
|
13243
|
+
...inputs.transitionCode ? { transitionCode: String(inputs.transitionCode) } : {}
|
|
13244
|
+
};
|
|
12884
13245
|
}
|
|
12885
13246
|
});
|
|
12886
13247
|
registerTopicOperation({
|
|
@@ -12904,35 +13265,6 @@ registerTopicOperation({
|
|
|
12904
13265
|
}
|
|
12905
13266
|
})
|
|
12906
13267
|
});
|
|
12907
|
-
registerTopicOperation({
|
|
12908
|
-
type: "qi/topic.outcome.confirm",
|
|
12909
|
-
can: "topic/outcome.confirm",
|
|
12910
|
-
operationType: "update-contract",
|
|
12911
|
-
confirmation: true,
|
|
12912
|
-
owner: "human",
|
|
12913
|
-
ability: "topic/update-contract",
|
|
12914
|
-
inputSchema: {
|
|
12915
|
-
type: "object",
|
|
12916
|
-
required: ["proposedOutcomeRecordId", "confirmationAuthorityDid", "confirmationReference"],
|
|
12917
|
-
additionalProperties: false,
|
|
12918
|
-
properties: {
|
|
12919
|
-
proposedOutcomeRecordId: { type: "string" },
|
|
12920
|
-
confirmationAuthorityDid: { type: "string", pattern: "^did:" },
|
|
12921
|
-
confirmationReference: { type: "string" },
|
|
12922
|
-
idempotencyKey: { type: "string" }
|
|
12923
|
-
}
|
|
12924
|
-
},
|
|
12925
|
-
buildPayload: (inputs) => ({
|
|
12926
|
-
patch: {
|
|
12927
|
-
outcome: {
|
|
12928
|
-
status: "achieved",
|
|
12929
|
-
outcomeRecordId: requiredString(inputs.proposedOutcomeRecordId, "proposedOutcomeRecordId"),
|
|
12930
|
-
confirmedBy: requiredString(inputs.confirmationAuthorityDid, "confirmationAuthorityDid"),
|
|
12931
|
-
confirmationReference: requiredString(inputs.confirmationReference, "confirmationReference")
|
|
12932
|
-
}
|
|
12933
|
-
}
|
|
12934
|
-
})
|
|
12935
|
-
});
|
|
12936
13268
|
registerTopicOperation({
|
|
12937
13269
|
type: "qi/topic.decision.record",
|
|
12938
13270
|
can: "topic/decision.record",
|
|
@@ -13341,6 +13673,60 @@ registerSemanticAction({
|
|
|
13341
13673
|
occurredAt: String(inputs.occurredAt || (/* @__PURE__ */ new Date()).toISOString())
|
|
13342
13674
|
})
|
|
13343
13675
|
});
|
|
13676
|
+
registerAction({
|
|
13677
|
+
type: "qi/topic.remind",
|
|
13678
|
+
can: "topic/reminder.deliver",
|
|
13679
|
+
displayName: "Send a Topic reminder",
|
|
13680
|
+
description: "Posts a reminder into the Topic thread and notifies the people responsible for it.",
|
|
13681
|
+
sideEffect: true,
|
|
13682
|
+
proof: { fields: ["deliveredAt"] },
|
|
13683
|
+
done: doneWhenCompleted,
|
|
13684
|
+
defaultRequiresConfirmation: false,
|
|
13685
|
+
executionOwner: "agent",
|
|
13686
|
+
riskTier: "low",
|
|
13687
|
+
requiredServices: ["topic"],
|
|
13688
|
+
eligibleForTimeTrigger: true,
|
|
13689
|
+
scheduling: {
|
|
13690
|
+
riskTier: "R0",
|
|
13691
|
+
misfirePolicies: ["run_once_immediately", "skip"],
|
|
13692
|
+
// Reminders never queue: two firings of the same reminder are the same
|
|
13693
|
+
// reminder, and delivering it twice is the failure mode, not the goal.
|
|
13694
|
+
overlapPolicies: ["skip"],
|
|
13695
|
+
approvalRequirement: "none",
|
|
13696
|
+
idempotencyStrategy: "idempotency_key",
|
|
13697
|
+
inputModes: ["resolve_at_fire"],
|
|
13698
|
+
runModes: ["new_run_per_occurrence"]
|
|
13699
|
+
},
|
|
13700
|
+
topic: topicMetadata(ALL_KINDS2, [], ["topic/manage-reminder"], "contextual"),
|
|
13701
|
+
inputSchema: {
|
|
13702
|
+
type: "object",
|
|
13703
|
+
required: ["recipients"],
|
|
13704
|
+
additionalProperties: false,
|
|
13705
|
+
properties: {
|
|
13706
|
+
recipients: { type: "array", items: { type: "string" } },
|
|
13707
|
+
message: { type: "string" },
|
|
13708
|
+
idempotencyKey: { type: "string" }
|
|
13709
|
+
}
|
|
13710
|
+
},
|
|
13711
|
+
outputSchema: [
|
|
13712
|
+
{ path: "deliveredAt", displayName: "Delivered at", type: "string" },
|
|
13713
|
+
{ path: "recipients", displayName: "Reminded", type: "string" }
|
|
13714
|
+
],
|
|
13715
|
+
run: async (inputs, ctx) => {
|
|
13716
|
+
const service = topicService(ctx);
|
|
13717
|
+
if (!service.deliverReminder) throw new Error("The host did not grant a Topic reminder delivery service");
|
|
13718
|
+
const recipients = requiredArray(inputs.recipients, "recipients");
|
|
13719
|
+
if (recipients.length === 0) throw new Error("A reminder needs at least one recipient");
|
|
13720
|
+
return {
|
|
13721
|
+
output: await service.deliverReminder({
|
|
13722
|
+
context: topicContext(ctx),
|
|
13723
|
+
recipients,
|
|
13724
|
+
message: String(inputs.message || ""),
|
|
13725
|
+
idempotencyKey: idempotencyKey("qi/topic.remind", inputs, ctx)
|
|
13726
|
+
})
|
|
13727
|
+
};
|
|
13728
|
+
}
|
|
13729
|
+
});
|
|
13344
13730
|
|
|
13345
13731
|
// src/core/lib/actionRegistry/actions/calendar/eventCreate.types.ts
|
|
13346
13732
|
var EMPTY = {
|
|
@@ -22462,6 +22848,12 @@ export {
|
|
|
22462
22848
|
ACTION_REGISTRY_VERSION,
|
|
22463
22849
|
generateActionManifest,
|
|
22464
22850
|
actionManifestIssues,
|
|
22851
|
+
ACTION_MANIFEST_V2_SCHEMA,
|
|
22852
|
+
ActionManifestV2VerificationError,
|
|
22853
|
+
canonicalizeManifestV2Payload,
|
|
22854
|
+
computeActionManifestV2Digest,
|
|
22855
|
+
signActionManifestV2,
|
|
22856
|
+
verifyActionManifestV2,
|
|
22465
22857
|
isBlankInputValue,
|
|
22466
22858
|
getMissingActionInputs,
|
|
22467
22859
|
SERVICE_VERBS,
|
|
@@ -22756,4 +23148,4 @@ export {
|
|
|
22756
23148
|
executeQueuedFlowAgentCoreCommands,
|
|
22757
23149
|
FlowAgentService
|
|
22758
23150
|
};
|
|
22759
|
-
//# sourceMappingURL=chunk-
|
|
23151
|
+
//# sourceMappingURL=chunk-NEOPTPDF.js.map
|