@tinycloud/share-sdk 1.2.0-beta.4 → 1.2.0-beta.6
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/{addressed-publish-BDaGyQA9.d.ts → addressed-publish-BnSBJ-MX.d.ts} +3 -1
- package/dist/{addressed-publish-DVvTlGog.d.cts → addressed-publish-DtcLNG2m.d.cts} +3 -1
- package/dist/artifact.cjs +88 -13
- package/dist/artifact.cjs.map +1 -1
- package/dist/artifact.d.cts +28 -8
- package/dist/artifact.d.ts +28 -8
- package/dist/artifact.js +84 -14
- package/dist/artifact.js.map +1 -1
- package/dist/index.cjs +128 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -4
- package/dist/index.d.ts +90 -4
- package/dist/index.js +123 -4
- package/dist/index.js.map +1 -1
- package/dist/share-index.cjs +21 -1
- package/dist/share-index.cjs.map +1 -1
- package/dist/share-index.js +21 -1
- package/dist/share-index.js.map +1 -1
- package/dist/share-root.cjs +119 -1
- package/dist/share-root.cjs.map +1 -1
- package/dist/share-root.d.cts +75 -13
- package/dist/share-root.d.ts +75 -13
- package/dist/share-root.js +117 -1
- package/dist/share-root.js.map +1 -1
- package/package.json +2 -2
package/dist/share-root.cjs
CHANGED
|
@@ -42,6 +42,8 @@ __export(share_root_entry_exports, {
|
|
|
42
42
|
ownerRootCacaoCid: () => ownerRootCacaoCid,
|
|
43
43
|
perShareNetworkIdFor: () => perShareNetworkIdFor,
|
|
44
44
|
planShareControlBatches: () => planShareControlBatches,
|
|
45
|
+
publishRootBearerLink: () => publishRootBearerLink,
|
|
46
|
+
revokeRootBearerLink: () => revokeRootBearerLink,
|
|
45
47
|
revokeShareGrant: () => revokeShareGrant,
|
|
46
48
|
runShareControlBatch: () => runShareControlBatch,
|
|
47
49
|
signShareKeyDelegation: () => signShareKeyDelegation
|
|
@@ -5356,6 +5358,20 @@ var v3TargetSchema = external_exports.object({
|
|
|
5356
5358
|
nodeAudience: external_exports.string().min(1),
|
|
5357
5359
|
spaceId: external_exports.string().refine(isCanonicalPathSegment, { message: "expected a canonical space id" })
|
|
5358
5360
|
}).strict();
|
|
5361
|
+
var ARTIFACT_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{2,62}$/;
|
|
5362
|
+
var artifactPinSchema = external_exports.object({
|
|
5363
|
+
v: external_exports.literal(1),
|
|
5364
|
+
artifactId: external_exports.string().regex(ARTIFACT_ID_PATTERN),
|
|
5365
|
+
version: external_exports.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
5366
|
+
/** SHA-256 (lowercase hex) of the exact `manifest.json` bytes. The manifest itself stays an owner-side record. */
|
|
5367
|
+
manifestSha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
5368
|
+
/** An addressed share reads one exact file, so exactly one entry: the stored bytes (ciphertext) it will fetch. */
|
|
5369
|
+
files: external_exports.array(external_exports.object({
|
|
5370
|
+
path: external_exports.string().min(1).max(255),
|
|
5371
|
+
sha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
5372
|
+
bytes: external_exports.number().int().nonnegative()
|
|
5373
|
+
}).strict()).length(1)
|
|
5374
|
+
}).strict();
|
|
5359
5375
|
var unsignedShareEnvelopeV3BaseSchema = external_exports.object({
|
|
5360
5376
|
version: external_exports.literal(3),
|
|
5361
5377
|
shareId: external_exports.string().min(1),
|
|
@@ -5375,7 +5391,13 @@ var unsignedShareEnvelopeV3BaseSchema = external_exports.object({
|
|
|
5375
5391
|
expiry: external_exports.string().datetime({ offset: true }),
|
|
5376
5392
|
display: displaySchema,
|
|
5377
5393
|
encrypted: external_exports.literal(true),
|
|
5378
|
-
metadata: contentMetadataSchema
|
|
5394
|
+
metadata: contentMetadataSchema,
|
|
5395
|
+
/**
|
|
5396
|
+
* TC-1428: an owner-signed statement that this share reads one write-once artifact version. Additive: absent on
|
|
5397
|
+
* every other share, and covered by the envelope signature because the signature spans the whole unsigned object.
|
|
5398
|
+
* The shape is checked here; its binding to the content source is `verifyArtifactShare` in share-sdk.
|
|
5399
|
+
*/
|
|
5400
|
+
artifactPin: artifactPinSchema.optional()
|
|
5379
5401
|
}).strict();
|
|
5380
5402
|
function validateV3Invariants(value, ctx) {
|
|
5381
5403
|
const actions = [...value.actions];
|
|
@@ -6956,6 +6978,35 @@ var ShareRoot = class _ShareRoot {
|
|
|
6956
6978
|
covers(expiresAt, now = this.#now()) {
|
|
6957
6979
|
return this.#key !== void 0 && now < this.expiresAt.getTime() && expiresAt.getTime() <= this.expiresAt.getTime();
|
|
6958
6980
|
}
|
|
6981
|
+
/**
|
|
6982
|
+
* Sign a 60-second `POST /revoke` invocation, by the share key, for one
|
|
6983
|
+
* delegation this root issued (a bearer link). Zero approvals. The Node
|
|
6984
|
+
* authorizes it because the share key is that delegation's delegator. The
|
|
6985
|
+
* root itself is never revoked this way: only the owner does that.
|
|
6986
|
+
*/
|
|
6987
|
+
async signLinkRevocation(input) {
|
|
6988
|
+
const key = this.#activeKey();
|
|
6989
|
+
if (typeof input.delegationCid !== "string" || !/^b[a-z2-7]+$/.test(input.delegationCid)) throw new ShareRootError("invalid-request", "delegation CID is invalid");
|
|
6990
|
+
if (input.delegationCid === this.cid) throw new ShareRootError("invalid-request", "the share key does not revoke its own root; the owner does");
|
|
6991
|
+
try {
|
|
6992
|
+
ed25519PublicKeyFromDidKey(input.nodeDid);
|
|
6993
|
+
} catch {
|
|
6994
|
+
throw new ShareRootError("invalid-request", "node DID must be an Ed25519 did:key");
|
|
6995
|
+
}
|
|
6996
|
+
const now = seconds(this.#now());
|
|
6997
|
+
const revocation = await signCompactUcanAuthorization({
|
|
6998
|
+
issuerDid: key.did,
|
|
6999
|
+
audienceDid: input.nodeDid,
|
|
7000
|
+
attenuation: { [`urn:cid:${input.delegationCid}`]: { "tinycloud.delegation/revoke": [{}] } },
|
|
7001
|
+
facts: [{}],
|
|
7002
|
+
proofs: [],
|
|
7003
|
+
notBefore: now,
|
|
7004
|
+
expiresAt: now + 60,
|
|
7005
|
+
nonce: `urn:uuid:${crypto.randomUUID()}`,
|
|
7006
|
+
sign: (bytes2) => key.sign(bytes2)
|
|
7007
|
+
});
|
|
7008
|
+
return revocation.authorization;
|
|
7009
|
+
}
|
|
6959
7010
|
/**
|
|
6960
7011
|
* Sign a bearer link: `kv/get` on one exact key under the prefix, to the
|
|
6961
7012
|
* link's own key, with this root as its only proof. It never outlives the
|
|
@@ -7029,6 +7080,8 @@ async function ensureShareRoot(input) {
|
|
|
7029
7080
|
|
|
7030
7081
|
// src/artifact.ts
|
|
7031
7082
|
var import_sha2563 = require("@noble/hashes/sha256");
|
|
7083
|
+
|
|
7084
|
+
// src/artifact-core.ts
|
|
7032
7085
|
function parseArtifactVersionPath(path) {
|
|
7033
7086
|
const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
|
|
7034
7087
|
if (match === null) return void 0;
|
|
@@ -7736,6 +7789,69 @@ async function runShareControlBatch(input) {
|
|
|
7736
7789
|
key.clear();
|
|
7737
7790
|
}
|
|
7738
7791
|
}
|
|
7792
|
+
|
|
7793
|
+
// src/share-root-link.ts
|
|
7794
|
+
var import_ed255196 = require("@noble/curves/ed25519");
|
|
7795
|
+
|
|
7796
|
+
// src/native.ts
|
|
7797
|
+
var NATIVE_SHARE_FRAGMENT_PARAMETER = "tc1";
|
|
7798
|
+
function canonicalViewerUrl(viewerOrigin) {
|
|
7799
|
+
const url = new URL(viewerOrigin);
|
|
7800
|
+
if (url.protocol !== "https:" || url.origin !== viewerOrigin || url.pathname !== "/" || url.search || url.hash) throw new TypeError("viewer origin must be a canonical HTTPS origin");
|
|
7801
|
+
url.pathname = "/viewer";
|
|
7802
|
+
return url;
|
|
7803
|
+
}
|
|
7804
|
+
|
|
7805
|
+
// src/share-root-link.ts
|
|
7806
|
+
async function publishRootBearerLink(input) {
|
|
7807
|
+
const fetchFn = input.fetch ?? ((url, init) => globalThis.fetch(url, init));
|
|
7808
|
+
const viewerUrl = canonicalViewerUrl(input.viewerOrigin);
|
|
7809
|
+
const secret = import_ed255196.ed25519.utils.randomPrivateKey();
|
|
7810
|
+
try {
|
|
7811
|
+
const publicKey = import_ed255196.ed25519.getPublicKey(secret);
|
|
7812
|
+
const linkDid = didKeyFromEd25519PublicKey(publicKey);
|
|
7813
|
+
const link = await input.root.signBearerLink({ linkDid, path: input.path, expiresAt: input.expiresAt });
|
|
7814
|
+
const response = await fetchFn(new URL("/delegate", input.root.nodeOrigin), { method: "POST", redirect: "error", headers: { Authorization: link.delegation.authorization } });
|
|
7815
|
+
if (!response.ok) throw new ShareRootError("node-refused", `the Node refused the link delegation: HTTP ${response.status} ${(await response.text()).slice(0, 120)}`, { rootCid: input.root.cid });
|
|
7816
|
+
const createdAt = /* @__PURE__ */ new Date();
|
|
7817
|
+
const shareData = {
|
|
7818
|
+
key: { kty: "OKP", crv: "Ed25519", x: toBase64Url(publicKey), d: toBase64Url(secret) },
|
|
7819
|
+
keyDid: `${linkDid}#${linkDid.slice("did:key:".length)}`,
|
|
7820
|
+
delegation: {
|
|
7821
|
+
cid: link.delegation.cid,
|
|
7822
|
+
delegateDID: linkDid,
|
|
7823
|
+
delegatorDID: input.root.keyDid,
|
|
7824
|
+
spaceId: input.root.spaceId,
|
|
7825
|
+
path: input.path,
|
|
7826
|
+
actions: ["tinycloud.kv/get"],
|
|
7827
|
+
expiry: link.expiresAt,
|
|
7828
|
+
isRevoked: false,
|
|
7829
|
+
allowSubDelegation: true,
|
|
7830
|
+
createdAt,
|
|
7831
|
+
parentCid: input.root.cid,
|
|
7832
|
+
authHeader: link.delegation.authorization
|
|
7833
|
+
},
|
|
7834
|
+
path: input.path,
|
|
7835
|
+
host: input.root.nodeOrigin,
|
|
7836
|
+
spaceId: input.root.spaceId,
|
|
7837
|
+
version: 1
|
|
7838
|
+
};
|
|
7839
|
+
const token = `tc1:${toBase64Url(new TextEncoder().encode(JSON.stringify(shareData)))}`;
|
|
7840
|
+
viewerUrl.hash = `${NATIVE_SHARE_FRAGMENT_PARAMETER}=${encodeURIComponent(token)}`;
|
|
7841
|
+
return { url: viewerUrl.toString(), delegationCid: link.delegation.cid, rootCid: input.root.cid, spaceId: input.root.spaceId, path: input.path, expiresAt: link.expiresAt };
|
|
7842
|
+
} finally {
|
|
7843
|
+
secret.fill(0);
|
|
7844
|
+
}
|
|
7845
|
+
}
|
|
7846
|
+
async function revokeRootBearerLink(input) {
|
|
7847
|
+
const fetchFn = input.fetch ?? ((url, init) => globalThis.fetch(url, init));
|
|
7848
|
+
const nodeDid = await nodeDidOf(input.root.nodeOrigin, fetchFn);
|
|
7849
|
+
const authorization = await input.root.signLinkRevocation({ delegationCid: input.delegationCid, nodeDid });
|
|
7850
|
+
const response = await fetchFn(new URL("/revoke", input.root.nodeOrigin), { method: "POST", redirect: "error", headers: { Authorization: authorization } });
|
|
7851
|
+
if (!response.ok) throw new ShareRootError("node-refused", `the Node refused the link revocation: HTTP ${response.status} ${(await response.text()).slice(0, 120)}`, { rootCid: input.root.cid });
|
|
7852
|
+
if (!await isRevokeReceiptFor(response, input.delegationCid)) throw new ShareRootError("invalid-request", "link revocation receipt does not confirm this delegation");
|
|
7853
|
+
return { revoked: true, cid: input.delegationCid };
|
|
7854
|
+
}
|
|
7739
7855
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7740
7856
|
0 && (module.exports = {
|
|
7741
7857
|
AGENT_SHARE_ROOT_MAX_LIFETIME_MS,
|
|
@@ -7760,6 +7876,8 @@ async function runShareControlBatch(input) {
|
|
|
7760
7876
|
ownerRootCacaoCid,
|
|
7761
7877
|
perShareNetworkIdFor,
|
|
7762
7878
|
planShareControlBatches,
|
|
7879
|
+
publishRootBearerLink,
|
|
7880
|
+
revokeRootBearerLink,
|
|
7763
7881
|
revokeShareGrant,
|
|
7764
7882
|
runShareControlBatch,
|
|
7765
7883
|
signShareKeyDelegation
|