@ggui-ai/registry-core 0.6.3 → 0.8.0

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.
Files changed (50) hide show
  1. package/dist/impls/memory-bundle-storage.d.ts.map +1 -1
  2. package/dist/impls/memory-bundle-storage.js +25 -22
  3. package/dist/impls/memory-registry-storage.d.ts.map +1 -1
  4. package/dist/impls/memory-registry-storage.js +47 -4
  5. package/dist/index.d.ts +8 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +8 -2
  8. package/dist/install-command.d.ts +25 -0
  9. package/dist/install-command.d.ts.map +1 -0
  10. package/dist/install-command.js +15 -0
  11. package/dist/interfaces/bundle-storage.d.ts +55 -31
  12. package/dist/interfaces/bundle-storage.d.ts.map +1 -1
  13. package/dist/interfaces/registry-storage.d.ts +106 -1
  14. package/dist/interfaces/registry-storage.d.ts.map +1 -1
  15. package/dist/mcp-tool-filters.d.ts +23 -0
  16. package/dist/mcp-tool-filters.d.ts.map +1 -0
  17. package/dist/mcp-tool-filters.js +14 -0
  18. package/dist/ops/delete-author-key.d.ts +45 -0
  19. package/dist/ops/delete-author-key.d.ts.map +1 -0
  20. package/dist/ops/delete-author-key.js +31 -0
  21. package/dist/ops/list-author-keys.d.ts +34 -0
  22. package/dist/ops/list-author-keys.d.ts.map +1 -0
  23. package/dist/ops/list-author-keys.js +45 -0
  24. package/dist/ops/list-versions.d.ts +19 -10
  25. package/dist/ops/list-versions.d.ts.map +1 -1
  26. package/dist/ops/list-versions.js +43 -8
  27. package/dist/ops/private-read-authz.d.ts +88 -0
  28. package/dist/ops/private-read-authz.d.ts.map +1 -0
  29. package/dist/ops/private-read-authz.js +58 -0
  30. package/dist/ops/publish.d.ts +68 -1
  31. package/dist/ops/publish.d.ts.map +1 -1
  32. package/dist/ops/publish.js +292 -16
  33. package/dist/ops/read.d.ts +28 -6
  34. package/dist/ops/read.d.ts.map +1 -1
  35. package/dist/ops/read.js +47 -7
  36. package/dist/ops/register-author-key.d.ts +13 -0
  37. package/dist/ops/register-author-key.d.ts.map +1 -1
  38. package/dist/ops/register-author-key.js +42 -0
  39. package/dist/ops/search.d.ts +13 -1
  40. package/dist/ops/search.d.ts.map +1 -1
  41. package/dist/ops/search.js +54 -2
  42. package/dist/testing/bundle-storage-contract.d.ts.map +1 -1
  43. package/dist/testing/bundle-storage-contract.js +61 -27
  44. package/dist/testing/registry-storage-contract.d.ts +1 -1
  45. package/dist/testing/registry-storage-contract.d.ts.map +1 -1
  46. package/dist/testing/registry-storage-contract.js +351 -1
  47. package/dist/types.d.ts +257 -17
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/types.js +79 -14
  50. package/package.json +20 -5
@@ -1 +1 @@
1
- {"version":3,"file":"memory-bundle-storage.d.ts","sourceRoot":"","sources":["../../src/impls/memory-bundle-storage.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAErE,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,aAAa,CA2Cf"}
1
+ {"version":3,"file":"memory-bundle-storage.d.ts","sourceRoot":"","sources":["../../src/impls/memory-bundle-storage.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,aAAa,CAkDf"}
@@ -3,38 +3,41 @@ export function inMemoryBundleStorage(options = {}) {
3
3
  const bundles = new Map();
4
4
  const signatures = new Map();
5
5
  const manifests = new Map();
6
- const key = (scope, name, version) => `${scope}/${name}/${version}`;
6
+ // Visibility segments the key (H1 prefix split) — a blob written
7
+ // `public` must be invisible to a `private` read of the same triple,
8
+ // exactly like the prefix-split object keys of the durable impls.
9
+ const key = (scope, name, version, visibility) => `${visibility}/${scope}/${name}/${version}`;
7
10
  return {
8
- async putBundle(scope, name, version, bytes) {
9
- bundles.set(key(scope, name, version), new Uint8Array(bytes));
10
- return this.bundleUrl(scope, name, version);
11
+ async putBundle(scope, name, version, visibility, bytes) {
12
+ bundles.set(key(scope, name, version, visibility), new Uint8Array(bytes));
13
+ return this.bundleUrl(scope, name, version, visibility);
11
14
  },
12
- async getBundle(scope, name, version) {
13
- const bytes = bundles.get(key(scope, name, version));
15
+ async getBundle(scope, name, version, visibility) {
16
+ const bytes = bundles.get(key(scope, name, version, visibility));
14
17
  return bytes === undefined ? null : new Uint8Array(bytes);
15
18
  },
16
- async putSignature(scope, name, version, signature) {
17
- signatures.set(key(scope, name, version), signature);
18
- return this.signatureUrl(scope, name, version);
19
+ async putSignature(scope, name, version, visibility, signature) {
20
+ signatures.set(key(scope, name, version, visibility), signature);
21
+ return this.signatureUrl(scope, name, version, visibility);
19
22
  },
20
- async getSignature(scope, name, version) {
21
- return signatures.get(key(scope, name, version)) ?? null;
23
+ async getSignature(scope, name, version, visibility) {
24
+ return signatures.get(key(scope, name, version, visibility)) ?? null;
22
25
  },
23
- async putManifest(scope, name, version, manifest) {
24
- manifests.set(key(scope, name, version), manifest);
25
- return this.manifestUrl(scope, name, version);
26
+ async putManifest(scope, name, version, visibility, manifest) {
27
+ manifests.set(key(scope, name, version, visibility), manifest);
28
+ return this.manifestUrl(scope, name, version, visibility);
26
29
  },
27
- async getManifest(scope, name, version) {
28
- return manifests.get(key(scope, name, version)) ?? null;
30
+ async getManifest(scope, name, version, visibility) {
31
+ return manifests.get(key(scope, name, version, visibility)) ?? null;
29
32
  },
30
- bundleUrl(scope, name, version) {
31
- return `${bundleHost}/bundles/${scope}/${name}/${version}/bundle.js`;
33
+ bundleUrl(scope, name, version, visibility) {
34
+ return `${bundleHost}/bundles/${visibility}/${scope}/${name}/${version}/bundle.js`;
32
35
  },
33
- signatureUrl(scope, name, version) {
34
- return `${bundleHost}/bundles/${scope}/${name}/${version}/bundle.js.sig`;
36
+ signatureUrl(scope, name, version, visibility) {
37
+ return `${bundleHost}/bundles/${visibility}/${scope}/${name}/${version}/bundle.js.sig`;
35
38
  },
36
- manifestUrl(scope, name, version) {
37
- return `${bundleHost}/bundles/${scope}/${name}/${version}/manifest.json`;
39
+ manifestUrl(scope, name, version, visibility) {
40
+ return `${bundleHost}/bundles/${visibility}/${scope}/${name}/${version}/manifest.json`;
38
41
  },
39
42
  };
40
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-registry-storage.d.ts","sourceRoot":"","sources":["../../src/impls/memory-registry-storage.ts"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAC;AAK3C,wBAAgB,uBAAuB,IAAI,eAAe,CAmHzD"}
1
+ {"version":3,"file":"memory-registry-storage.d.ts","sourceRoot":"","sources":["../../src/impls/memory-registry-storage.ts"],"names":[],"mappings":"AAoBA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAC;AAM3C,wBAAgB,uBAAuB,IAAI,eAAe,CA2JzD"}
@@ -1,4 +1,5 @@
1
1
  import { AuthorKeyAlreadyExistsError, } from '../interfaces/registry-storage.js';
2
+ import { matchesMcpToolFilters } from '../mcp-tool-filters.js';
2
3
  const DEFAULT_LIMIT = 50;
3
4
  const MAX_LIMIT = 200;
4
5
  export function inMemoryRegistryStorage() {
@@ -6,8 +7,12 @@ export function inMemoryRegistryStorage() {
6
7
  const versions = new Map();
7
8
  const authorKeys = new Map();
8
9
  const compiledBlobs = new Map();
10
+ const scopeOwners = new Map();
9
11
  const versionKey = (artifactId, version) => `${artifactId}@${version}`;
10
- const authorKey = (subject, keyId) => `${subject}/${keyId}`;
12
+ // JSON tuple — unambiguous for ANY subject/keyId contents. Subjects
13
+ // are operator-defined free text, so a `${subject}/${keyId}` composite
14
+ // would make ('team', …) and ('team/alice', …) collide or leak.
15
+ const authorKey = (subject, keyId) => JSON.stringify([subject, keyId]);
11
16
  return {
12
17
  async getArtifactMetadata(artifactId) {
13
18
  return metadata.get(artifactId) ?? null;
@@ -92,6 +97,36 @@ export function inMemoryRegistryStorage() {
92
97
  });
93
98
  return { ok: true, mode: 'dedup' };
94
99
  },
100
+ async getScopeOwner(scope) {
101
+ return scopeOwners.get(scope) ?? null;
102
+ },
103
+ async claimScope(row) {
104
+ // First-writer-wins. The check-and-set pair runs with no `await`
105
+ // between them, so the single-threaded event loop makes it
106
+ // atomic — two racing claims resolve strictly one-after-another.
107
+ if (scopeOwners.has(row.scope)) {
108
+ return { conflict: true };
109
+ }
110
+ scopeOwners.set(row.scope, row);
111
+ return { ok: true };
112
+ },
113
+ async updateScopeOwner(row, expect) {
114
+ // Compare-and-set against the caller's read snapshot. The
115
+ // check-and-set pair runs with no interleaving `await`, so the
116
+ // event loop makes it atomic (same discipline as claimScope).
117
+ const current = scopeOwners.get(row.scope);
118
+ if ('absent' in expect) {
119
+ if (current !== undefined)
120
+ return { conflict: true };
121
+ }
122
+ else if (current === undefined ||
123
+ current.ownerSubject !== expect.ownerSubject ||
124
+ current.verification !== expect.verification) {
125
+ return { conflict: true };
126
+ }
127
+ scopeOwners.set(row.scope, row);
128
+ return { ok: true };
129
+ },
95
130
  async getAuthorKey(subject, keyId) {
96
131
  return authorKeys.get(authorKey(subject, keyId)) ?? null;
97
132
  },
@@ -103,14 +138,20 @@ export function inMemoryRegistryStorage() {
103
138
  authorKeys.set(key, row);
104
139
  },
105
140
  async listAuthorKeys(subject) {
106
- const prefix = `${subject}/`;
141
+ // Row-field filter, not key-prefix matching — the row's own
142
+ // `subject` is the only unambiguous ownership signal.
107
143
  const matches = [];
108
- for (const [key, row] of authorKeys) {
109
- if (key.startsWith(prefix))
144
+ for (const row of authorKeys.values()) {
145
+ if (row.subject === subject)
110
146
  matches.push(row);
111
147
  }
112
148
  return matches;
113
149
  },
150
+ async deleteAuthorKey(subject, keyId) {
151
+ // Map#delete returns whether an entry existed — exactly the
152
+ // contract's `deleted` signal.
153
+ return authorKeys.delete(authorKey(subject, keyId));
154
+ },
114
155
  };
115
156
  }
116
157
  function clampLimit(limit) {
@@ -137,6 +178,8 @@ function rowMatchesFilter(row, q) {
137
178
  return false;
138
179
  if (q.hook !== undefined && row.hook !== q.hook)
139
180
  return false;
181
+ if (!matchesMcpToolFilters(row.mcpTools, q))
182
+ return false;
140
183
  if (q.tag !== undefined) {
141
184
  if (row.tags === undefined || !row.tags.includes(q.tag))
142
185
  return false;
package/dist/index.d.ts CHANGED
@@ -9,17 +9,22 @@
9
9
  */
10
10
  export type { AuthnContext } from './interfaces/authn.js';
11
11
  export type { BundleStorage } from './interfaces/bundle-storage.js';
12
- export { AuthorKeyAlreadyExistsError, type PutAuthorKeyOptions, type RegistryStorage, } from './interfaces/registry-storage.js';
13
- export { ARTIFACTS_METADATA_SK, type ArtifactKind, type ArtifactScanFilter, type ArtifactVersionRow, type ArtifactsMetadataRow, type AuthorKeyRow, type CompiledBlobRow, type ErrorBody, LIST_VERSIONS_ERROR_CODES, type ListVersionsErrorBody, type ListVersionsErrorCode, type ListVersionsResponse, PUBLISH_ERROR_CODES, type PublishErrorBody, type PublishErrorCode, type PublishRequestBody, type PublishResponseBody, READ_ERROR_CODES, type ReadErrorBody, type ReadErrorCode, type ReadPkgResponse, REGISTER_AUTHOR_KEY_ERROR_CODES, type RegisterAuthorKeyErrorBody, type RegisterAuthorKeyErrorCode, type RegisterAuthorKeyRequestBody, type RegisterAuthorKeyResponseBody, SEARCH_ERROR_CODES, SEARCH_SORT_OPTIONS, type SearchErrorBody, type SearchErrorCode, type SearchResponse, type SearchResultEntry, type SearchSort, type VersionListEntry, type Visibility, } from './types.js';
12
+ export { AuthorKeyAlreadyExistsError, type PutAuthorKeyOptions, type RegistryStorage, type ScopeOwnerExpectation, } from './interfaces/registry-storage.js';
13
+ export { ARTIFACTS_METADATA_SK, type ArtifactKind, type ArtifactScanFilter, type ArtifactVersionRow, type ArtifactsMetadataRow, type AuthorKeyListEntry, type AuthorKeyRow, type CompiledBlobRow, DELETE_AUTHOR_KEY_ERROR_CODES, type DeleteAuthorKeyErrorBody, type DeleteAuthorKeyErrorCode, type DeleteAuthorKeyResponseBody, type ErrorBody, LIST_AUTHOR_KEYS_ERROR_CODES, type ListAuthorKeysErrorBody, type ListAuthorKeysErrorCode, type ListAuthorKeysResponseBody, LIST_VERSIONS_ERROR_CODES, type ListVersionsErrorBody, type ListVersionsErrorCode, type ListVersionsResponse, PUBLISH_ERROR_CODES, type PublishErrorBody, type PublishErrorCode, type PublishRequestBody, type PublishResponseBody, READ_ERROR_CODES, type ReadErrorBody, type ReadErrorCode, type ReadPkgResponse, REGISTER_AUTHOR_KEY_ERROR_CODES, type RegisterAuthorKeyErrorBody, type RegisterAuthorKeyErrorCode, type RegisterAuthorKeyRequestBody, type RegisterAuthorKeyResponseBody, SAN_ALLOWLIST_INVALID, type SanAllowlistInvalid, SCOPE_VERIFICATIONS, type ScopeOwnerRow, type ScopeVerification, SEARCH_ERROR_CODES, SEARCH_SORT_OPTIONS, unauthorizedErrorBody, type SearchErrorBody, type SearchErrorCode, type SearchResponse, type SearchResultEntry, type SearchSort, type VersionListEntry, type Visibility, } from './types.js';
14
14
  export { compileBlueprint, type CompileBlueprintErr, type CompileBlueprintOk, type CompileBlueprintResult, } from './ops/compile.js';
15
15
  export { checkConformance, MAX_BLUEPRINT_SOURCE_BYTES, type BlueprintProbeRunner, type ConformanceError, type ConformanceErrorCode, type ConformanceFailureCode, type ConformanceRequestPayload, type ConformanceResponseBody, } from './ops/conformance.js';
16
- export { publishArtifact, MAX_BUNDLE_BYTES, type PublishArtifactDeps, type PublishArtifactInput, type PublishArtifactResult, } from './ops/publish.js';
16
+ export { publishArtifact, MAX_BUNDLE_BYTES, RESERVED_SCOPES, type PublishArtifactDeps, type PublishArtifactInput, type PublishArtifactResult, type VerifiedEmailResolver, } from './ops/publish.js';
17
17
  export { readArtifact, type ReadArtifactDeps, type ReadArtifactInput, type ReadArtifactResult, } from './ops/read.js';
18
+ export { artifactScope, canReadPrivateArtifact, createScopeOwnerResolver, } from './ops/private-read-authz.js';
18
19
  export { listArtifactVersions, type ListArtifactVersionsDeps, type ListArtifactVersionsInput, type ListArtifactVersionsResult, } from './ops/list-versions.js';
19
20
  export { searchArtifacts, type SearchArtifactsDeps, type SearchArtifactsInput, type SearchArtifactsResult, } from './ops/search.js';
20
21
  export { registerAuthorKey, type RegisterAuthorKeyDeps, type RegisterAuthorKeyInput, type RegisterAuthorKeyResult, } from './ops/register-author-key.js';
22
+ export { listAuthorKeys, type ListAuthorKeysDeps, type ListAuthorKeysResult, } from './ops/list-author-keys.js';
23
+ export { deleteAuthorKey, type DeleteAuthorKeyDeps, type DeleteAuthorKeyInput, type DeleteAuthorKeyResult, } from './ops/delete-author-key.js';
21
24
  export { inMemoryRegistryStorage } from './impls/memory-registry-storage.js';
22
25
  export { inMemoryBundleStorage, type InMemoryBundleStorageOptions, } from './impls/memory-bundle-storage.js';
26
+ export { matchesMcpToolFilters } from './mcp-tool-filters.js';
27
+ export { installCommand, type InstallCommandOptions, } from './install-command.js';
23
28
  export { compareSemver } from './utils/semver.js';
24
29
  export { base64Encode, safeBase64Decode, sha384Base64 } from './utils/base64.js';
25
30
  export type { Ed25519Signature, GadgetSignature } from '@ggui-ai/gadget-signing';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EACL,qBAAqB,EACrB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,GAChC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjF,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EACL,qBAAqB,EACrB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,6BAA6B,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,SAAS,EACd,4BAA4B,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,mBAAmB,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,GAChC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjF,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -9,18 +9,24 @@
9
9
  */
10
10
  export { AuthorKeyAlreadyExistsError, } from './interfaces/registry-storage.js';
11
11
  // Types — rows + wire shapes
12
- export { ARTIFACTS_METADATA_SK, LIST_VERSIONS_ERROR_CODES, PUBLISH_ERROR_CODES, READ_ERROR_CODES, REGISTER_AUTHOR_KEY_ERROR_CODES, SEARCH_ERROR_CODES, SEARCH_SORT_OPTIONS, } from './types.js';
12
+ export { ARTIFACTS_METADATA_SK, DELETE_AUTHOR_KEY_ERROR_CODES, LIST_AUTHOR_KEYS_ERROR_CODES, LIST_VERSIONS_ERROR_CODES, PUBLISH_ERROR_CODES, READ_ERROR_CODES, REGISTER_AUTHOR_KEY_ERROR_CODES, SAN_ALLOWLIST_INVALID, SCOPE_VERIFICATIONS, SEARCH_ERROR_CODES, SEARCH_SORT_OPTIONS, unauthorizedErrorBody, } from './types.js';
13
13
  // Operations
14
14
  export { compileBlueprint, } from './ops/compile.js';
15
15
  export { checkConformance, MAX_BLUEPRINT_SOURCE_BYTES, } from './ops/conformance.js';
16
- export { publishArtifact, MAX_BUNDLE_BYTES, } from './ops/publish.js';
16
+ export { publishArtifact, MAX_BUNDLE_BYTES, RESERVED_SCOPES, } from './ops/publish.js';
17
17
  export { readArtifact, } from './ops/read.js';
18
+ export { artifactScope, canReadPrivateArtifact, createScopeOwnerResolver, } from './ops/private-read-authz.js';
18
19
  export { listArtifactVersions, } from './ops/list-versions.js';
19
20
  export { searchArtifacts, } from './ops/search.js';
20
21
  export { registerAuthorKey, } from './ops/register-author-key.js';
22
+ export { listAuthorKeys, } from './ops/list-author-keys.js';
23
+ export { deleteAuthorKey, } from './ops/delete-author-key.js';
21
24
  // In-memory impls
22
25
  export { inMemoryRegistryStorage } from './impls/memory-registry-storage.js';
23
26
  export { inMemoryBundleStorage, } from './impls/memory-bundle-storage.js';
27
+ // Shared scan-filter semantics
28
+ export { matchesMcpToolFilters } from './mcp-tool-filters.js';
24
29
  // Utils
30
+ export { installCommand, } from './install-command.js';
25
31
  export { compareSemver } from './utils/semver.js';
26
32
  export { base64Encode, safeBase64Decode, sha384Base64 } from './utils/base64.js';
@@ -0,0 +1,25 @@
1
+ import type { ArtifactKind } from './types.js';
2
+ export interface InstallCommandOptions {
3
+ /**
4
+ * Registry origin to pin via an explicit `--registry=<url>` flag —
5
+ * pass the URL the artifact was discovered on (the same origin the
6
+ * search/read endpoints were queried against). When provided, the
7
+ * emitted command installs from exactly that registry instead of
8
+ * whatever the CLI's ambient default resolves to; when omitted, the
9
+ * flag is left off and the CLI default applies.
10
+ */
11
+ readonly registryHost?: string;
12
+ }
13
+ /**
14
+ * Compose the canonical CLI install command for a published artifact:
15
+ *
16
+ * ggui <kind> install <scope>/<name>@<version> [--registry=<url>]
17
+ *
18
+ * Same shape the publish flow reports back after a successful publish,
19
+ * so every surface that displays an install command agrees on one
20
+ * wording. Pure string composition — callers are responsible for
21
+ * validating `artifactId` (`@scope/name`) and `version` (semver)
22
+ * before display; this function does not re-validate.
23
+ */
24
+ export declare function installCommand(kind: ArtifactKind, artifactId: string, version: string, opts?: InstallCommandOptions): string;
25
+ //# sourceMappingURL=install-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-command.d.ts","sourceRoot":"","sources":["../src/install-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,qBAAqB;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,MAAM,CAIR"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Compose the canonical CLI install command for a published artifact:
3
+ *
4
+ * ggui <kind> install <scope>/<name>@<version> [--registry=<url>]
5
+ *
6
+ * Same shape the publish flow reports back after a successful publish,
7
+ * so every surface that displays an install command agrees on one
8
+ * wording. Pure string composition — callers are responsible for
9
+ * validating `artifactId` (`@scope/name`) and `version` (semver)
10
+ * before display; this function does not re-validate.
11
+ */
12
+ export function installCommand(kind, artifactId, version, opts = {}) {
13
+ const registry = opts.registryHost !== undefined ? ` --registry=${opts.registryHost}` : '';
14
+ return `ggui ${kind} install ${artifactId}@${version}${registry}`;
15
+ }
@@ -2,8 +2,8 @@
2
2
  * `BundleStorage` — bundle + signature + manifest blob storage. A
3
3
  * hosted implementation may serve blobs from object storage behind a
4
4
  * CDN; the open-source server backs it with the filesystem under
5
- * `<root>/bundles/<scope>/<name>/<version>/`. A memory impl is
6
- * provided for tests.
5
+ * `<root>/bundles/<visibility>/<scope>/<name>/<version>/`. A memory
6
+ * impl is provided for tests.
7
7
  *
8
8
  * Each `put*` method returns the fully-qualified URL the consumer
9
9
  * (iframe runtime, install CLI) can fetch. The URL prefix is
@@ -11,17 +11,33 @@
11
11
  * CDN-fronted implementation, or `http://localhost:9001` (or
12
12
  * whatever the server is bound to) for the open-source server.
13
13
  *
14
- * Bundles are immutable post-publish. Responses MUST emit
15
- * `Cache-Control: public, max-age=31536000, immutable` — SRI integrity
16
- * depends on it. The OSS server's bundle route sets this header
17
- * explicitly; a CDN-fronted implementation sets it via its cache
18
- * policy.
14
+ * ## Visibility-split key layout (load-bearing)
15
+ *
16
+ * Every blob lives under a visibility-segmented key:
17
+ *
18
+ * bundles/public/<scope>/<name>/<version>/{bundle.js,bundle.js.sig,manifest.json}
19
+ * bundles/private/<scope>/<name>/<version>/{...}
20
+ *
21
+ * Placement IS the access-control boundary: the `bundles/public/`
22
+ * prefix may be served anonymously (CDN, static route); the
23
+ * `bundles/private/` prefix MUST only be reachable through an
24
+ * authenticated route that authorizes the caller against the
25
+ * artifact's publisher or scope owner. An impl that flattens the two
26
+ * prefixes back together silently republishes every private artifact.
27
+ *
28
+ * Bundles are immutable post-publish. Public-prefix responses MUST
29
+ * emit `Cache-Control: public, max-age=31536000, immutable` — SRI
30
+ * integrity depends on it. Private-prefix responses stay immutable but
31
+ * MUST NOT be shared-cacheable (`Cache-Control: private, …`). The OSS
32
+ * server's bundle routes set these headers explicitly; a CDN-fronted
33
+ * implementation sets the public policy on its cache behavior.
19
34
  *
20
35
  * ## Protocol & Contract Bar
21
36
  *
22
37
  * **Parties:**
23
38
  * - Producer: {@link publishArtifact} writes bundle (gadgets),
24
- * signature (gadgets), and manifest (always) on every publish.
39
+ * signature (gadgets), and manifest (always) on every publish, at
40
+ * the key the manifest's `visibility` selects.
25
41
  * - Consumer: iframe-runtime (bundleUrl), install CLI (signatureUrl,
26
42
  * manifestUrl), audit tooling (manifestUrl on yanked versions).
27
43
  *
@@ -31,49 +47,57 @@
31
47
  * per-version row immutability invariant on {@link RegistryStorage}
32
48
  * prevents true re-publishes; the bundle-storage layer needs no
33
49
  * conflict semantics).
50
+ * - Key composition MUST segment on `visibility` — a blob written
51
+ * `public` is invisible to a `private` read of the same triple, and
52
+ * vice versa.
34
53
  * - URL composition methods (`bundleUrl`, `signatureUrl`,
35
- * `manifestUrl`) MUST be pure — no I/O, no async. Consumers cache
36
- * URLs liberally.
54
+ * `manifestUrl`) MUST be pure — no I/O, no async — and MUST embed
55
+ * the same visibility segment the corresponding `put*` used, so the
56
+ * persisted row URLs point at the blob's real location. Consumers
57
+ * cache URLs liberally.
37
58
  *
38
59
  * **Failure mode:**
39
60
  * - Transport-level failures throw; the publish op wraps and returns
40
61
  * 500.
41
- * - Missing-blob reads return `null`; never throw.
62
+ * - Missing-blob reads return `null`; never throw. A visibility
63
+ * mismatch reads as a miss.
42
64
  *
43
65
  * **Observable violation:**
44
66
  * - Contract test {@link bundleStorageContract} covers: bundle
45
67
  * round-trip preserves bytes; signature round-trip preserves the
46
68
  * structured object; manifest round-trip preserves the full
47
- * discriminated-union shape; URL methods compose without side effects;
48
- * missing reads return null.
69
+ * discriminated-union shape; URL methods compose without side effects
70
+ * and embed the visibility segment; missing reads return null;
71
+ * cross-visibility reads return null.
49
72
  */
50
73
  import type { ArtifactManifest } from '@ggui-ai/artifact-manifest';
51
74
  import type { GadgetSignature } from '@ggui-ai/gadget-signing';
75
+ import type { Visibility } from '../types.js';
52
76
  export interface BundleStorage {
53
- /** Write gadget bundle bytes. Returns the public URL. */
54
- putBundle(scope: string, name: string, version: string, bytes: Uint8Array): Promise<string>;
55
- /** Read gadget bundle bytes. `null` on miss. */
56
- getBundle(scope: string, name: string, version: string): Promise<Uint8Array | null>;
77
+ /** Write gadget bundle bytes. Returns the fetch URL. */
78
+ putBundle(scope: string, name: string, version: string, visibility: Visibility, bytes: Uint8Array): Promise<string>;
79
+ /** Read gadget bundle bytes. `null` on miss (including visibility mismatch). */
80
+ getBundle(scope: string, name: string, version: string, visibility: Visibility): Promise<Uint8Array | null>;
57
81
  /**
58
- * Write the signature envelope. Returns the public URL.
82
+ * Write the signature envelope. Returns the fetch URL.
59
83
  *
60
84
  * The envelope is a {@link GadgetSignature} — a discriminated union
61
85
  * over `algorithm` (`ed25519` for private gadgets, `sigstore-cosign`
62
86
  * for public). Impls serialize via `JSON.stringify(signature)` and
63
87
  * store the resulting bytes verbatim.
64
88
  */
65
- putSignature(scope: string, name: string, version: string, signature: GadgetSignature): Promise<string>;
66
- /** Read the signature envelope. `null` on miss. */
67
- getSignature(scope: string, name: string, version: string): Promise<GadgetSignature | null>;
68
- /** Write the manifest verbatim. Returns the public URL. */
69
- putManifest(scope: string, name: string, version: string, manifest: ArtifactManifest): Promise<string>;
70
- /** Read the manifest. `null` on miss. */
71
- getManifest(scope: string, name: string, version: string): Promise<ArtifactManifest | null>;
72
- /** Compose the public bundle URL. No I/O. */
73
- bundleUrl(scope: string, name: string, version: string): string;
74
- /** Compose the public signature URL. No I/O. */
75
- signatureUrl(scope: string, name: string, version: string): string;
76
- /** Compose the public manifest URL. No I/O. */
77
- manifestUrl(scope: string, name: string, version: string): string;
89
+ putSignature(scope: string, name: string, version: string, visibility: Visibility, signature: GadgetSignature): Promise<string>;
90
+ /** Read the signature envelope. `null` on miss (including visibility mismatch). */
91
+ getSignature(scope: string, name: string, version: string, visibility: Visibility): Promise<GadgetSignature | null>;
92
+ /** Write the manifest verbatim. Returns the fetch URL. */
93
+ putManifest(scope: string, name: string, version: string, visibility: Visibility, manifest: ArtifactManifest): Promise<string>;
94
+ /** Read the manifest. `null` on miss (including visibility mismatch). */
95
+ getManifest(scope: string, name: string, version: string, visibility: Visibility): Promise<ArtifactManifest | null>;
96
+ /** Compose the bundle URL (embeds the visibility segment). No I/O. */
97
+ bundleUrl(scope: string, name: string, version: string, visibility: Visibility): string;
98
+ /** Compose the signature URL (embeds the visibility segment). No I/O. */
99
+ signatureUrl(scope: string, name: string, version: string, visibility: Visibility): string;
100
+ /** Compose the manifest URL (embeds the visibility segment). No I/O. */
101
+ manifestUrl(scope: string, name: string, version: string, visibility: Visibility): string;
78
102
  }
79
103
  //# sourceMappingURL=bundle-storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-storage.d.ts","sourceRoot":"","sources":["../../src/interfaces/bundle-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5F,gDAAgD;IAChD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAEpF;;;;;;;OAOG;IACH,YAAY,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,mDAAmD;IACnD,YAAY,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAEnC,2DAA2D;IAC3D,WAAW,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,yCAAyC;IACzC,WAAW,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAEpC,6CAA6C;IAC7C,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAChE,gDAAgD;IAChD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACnE,+CAA+C;IAC/C,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CACnE"}
1
+ {"version":3,"file":"bundle-storage.d.ts","sourceRoot":"","sources":["../../src/interfaces/bundle-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,SAAS,CACP,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,gFAAgF;IAChF,SAAS,CACP,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAE9B;;;;;;;OAOG;IACH,YAAY,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,mFAAmF;IACnF,YAAY,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAEnC,0DAA0D;IAC1D,WAAW,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,yEAAyE;IACzE,WAAW,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAEpC,sEAAsE;IACtE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;IACxF,yEAAyE;IACzE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;IAC3F,wEAAwE;IACxE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;CAC3F"}
@@ -27,6 +27,23 @@
27
27
  * at the storage layer. Implementations
28
28
  * MUST NOT overwrite on conflict — per-version immutability is a
29
29
  * load-bearing registry invariant.
30
+ * - {@link claimScope} MUST be an atomic first-writer-wins conditional
31
+ * create: when two claims race on the same scope, EXACTLY one wins
32
+ * and the loser observes `{ conflict: true }` with the winner's row
33
+ * left untouched. Scope ownership is the publish-authorization
34
+ * invariant — a lost race that overwrote the winner would silently
35
+ * reassign every future publish under that scope.
36
+ * - {@link getScopeOwner} MUST observe a completed {@link claimScope}
37
+ * immediately (read-your-writes strong). The publish gate's
38
+ * claim-conflict path re-reads to learn the winner; a read that can
39
+ * lag a durable claim would fail the losing racer's publish with a
40
+ * spurious storage-inconsistency error.
41
+ * - {@link updateScopeOwner} MUST be conditional on the caller's read
42
+ * snapshot (`expect`): the write lands only when the stored row still
43
+ * matches (or is still absent, for `{ absent: true }`). On mismatch
44
+ * it returns `{ conflict: true }` with the stored row untouched —
45
+ * an operator rewrite MUST NOT clobber a concurrent transfer or a
46
+ * racing first-publish claim.
30
47
  * - {@link getArtifactMetadata} / {@link getArtifactVersion} MUST return
31
48
  * exactly what was last written. `null` on miss; throw on transport
32
49
  * failure (caller decides retry).
@@ -36,6 +53,13 @@
36
53
  * rows MUST come back ordered by `publishedAt` descending (newest
37
54
  * first), globally correct across the full cursor chain. Without an
38
55
  * `order`, consumers MUST treat ordering as non-deterministic.
56
+ * - {@link scanArtifacts} MUST apply the `tool` / `server` filter
57
+ * dimensions with the shared semantics of `matchesMcpToolFilters`:
58
+ * `tool` matches any binding entry with that tool name; `server`
59
+ * matches entries declaring that server (bare entries never match);
60
+ * together they require one entry with exactly that (server, tool)
61
+ * pair. Case-sensitive exact, AND-composed with every other
62
+ * dimension.
39
63
  *
40
64
  * **Failure mode:**
41
65
  * - Transport-level failures (store throttling, disk full) throw.
@@ -48,10 +72,11 @@
48
72
  * round-trip preservation, idempotent {@link putArtifactMetadata},
49
73
  * `putArtifactVersionIfAbsent` rejects on collision, missing returns
50
74
  * null, `listAuthorKeys` returns only keys for the queried subject,
75
+ * `deleteAuthorKey` true/false idempotency + per-subject isolation,
51
76
  * and `order: 'recent'` newest-first ordering (single page + across
52
77
  * the cursor chain).
53
78
  */
54
- import type { ArtifactScanFilter, ArtifactVersionRow, ArtifactsMetadataRow, AuthorKeyRow, CompiledBlobRow } from '../types.js';
79
+ import type { ArtifactScanFilter, ArtifactVersionRow, ArtifactsMetadataRow, AuthorKeyRow, CompiledBlobRow, ScopeOwnerRow } from '../types.js';
55
80
  /**
56
81
  * Optional flags for {@link RegistryStorage.putAuthorKey}.
57
82
  *
@@ -79,6 +104,18 @@ export declare class AuthorKeyAlreadyExistsError extends Error {
79
104
  readonly keyId: string;
80
105
  constructor(subject: string, keyId: string);
81
106
  }
107
+ /**
108
+ * The caller's read snapshot for {@link RegistryStorage.updateScopeOwner}
109
+ * — either the `(ownerSubject, verification)` pair the caller read, or
110
+ * an assertion that no row exists yet (`{ absent: true }`, the operator
111
+ * seed path).
112
+ */
113
+ export type ScopeOwnerExpectation = {
114
+ readonly ownerSubject: string;
115
+ readonly verification: ScopeOwnerRow['verification'];
116
+ } | {
117
+ readonly absent: true;
118
+ };
82
119
  export interface RegistryStorage {
83
120
  getArtifactMetadata(artifactId: string): Promise<ArtifactsMetadataRow | null>;
84
121
  putArtifactMetadata(row: ArtifactsMetadataRow): Promise<void>;
@@ -92,6 +129,10 @@ export interface RegistryStorage {
92
129
  * When `filter.order` is `'recent'`, rows MUST be returned newest
93
130
  * first by `publishedAt`, globally correct across the full cursor
94
131
  * chain — see the Obligations section above.
132
+ *
133
+ * `filter.tool` / `filter.server` follow the shared MCP-binding
134
+ * filter semantics (`matchesMcpToolFilters`) — see the Obligations
135
+ * section above.
95
136
  */
96
137
  scanArtifacts(filter: ArtifactScanFilter): Promise<{
97
138
  readonly rows: readonly ArtifactsMetadataRow[];
@@ -201,6 +242,56 @@ export interface RegistryStorage {
201
242
  ok: false;
202
243
  reason: 'version_exists';
203
244
  }>;
245
+ /**
246
+ * Fetch the ownership row for `scope` (leading `@` included, e.g.
247
+ * `@acme`). Returns `null` when the scope is unclaimed.
248
+ *
249
+ * MUST be read-your-writes strong with respect to {@link claimScope}
250
+ * and {@link updateScopeOwner} — see the Obligations section above.
251
+ */
252
+ getScopeOwner(scope: string): Promise<ScopeOwnerRow | null>;
253
+ /**
254
+ * Atomic first-writer-wins claim — creates the ownership row only
255
+ * when no row exists for `row.scope`. On conflict (a row already
256
+ * exists, including one that landed in a concurrent race) returns
257
+ * `{ conflict: true }` WITHOUT touching the existing row.
258
+ *
259
+ * The publish op claims on the caller's first publish into an
260
+ * unclaimed scope. Consumers MUST NOT pre-check with
261
+ * {@link getScopeOwner} + claim as a substitute for handling
262
+ * `conflict` — the conditional create is the only race-safe
263
+ * primitive (re-read on conflict instead).
264
+ */
265
+ claimScope(row: ScopeOwnerRow): Promise<{
266
+ ok: true;
267
+ } | {
268
+ conflict: true;
269
+ }>;
270
+ /**
271
+ * Conditional full-row put of the ownership row — a compare-and-set
272
+ * against the caller's read snapshot.
273
+ *
274
+ * `expect` states what the caller believes is stored:
275
+ * - `{ ownerSubject, verification }` — the row MUST still carry
276
+ * exactly this pair (the snapshot identity of an ownership row).
277
+ * - `{ absent: true }` — no row may exist yet (operator seeding).
278
+ *
279
+ * On mismatch the write is refused with `{ conflict: true }` and the
280
+ * stored row is untouched — the caller re-reads and retries. This is
281
+ * the structural defense against read-modify-write races between two
282
+ * operators, or between an operator write and a concurrent
283
+ * first-publish claim.
284
+ *
285
+ * Operator-only caller: verification flips and ownership transfers
286
+ * (including seeding rows for reserved scopes, which are never
287
+ * first-publish-claimable). The publish path MUST NOT call this —
288
+ * {@link claimScope} is its only write.
289
+ */
290
+ updateScopeOwner(row: ScopeOwnerRow, expect: ScopeOwnerExpectation): Promise<{
291
+ ok: true;
292
+ } | {
293
+ conflict: true;
294
+ }>;
204
295
  getAuthorKey(subject: string, keyId: string): Promise<AuthorKeyRow | null>;
205
296
  /**
206
297
  * Write an AuthorKey row. With `options.ifNotExists === true`, the
@@ -211,5 +302,19 @@ export interface RegistryStorage {
211
302
  */
212
303
  putAuthorKey(row: AuthorKeyRow, options?: PutAuthorKeyOptions): Promise<void>;
213
304
  listAuthorKeys(subject: string): Promise<readonly AuthorKeyRow[]>;
305
+ /**
306
+ * Hard-delete the row for `(subject, keyId)`. Returns `true` when a
307
+ * row existed and was removed, `false` when no row existed — the
308
+ * caller-visible idempotency signal for the delete op's
309
+ * `deleted: false` response. Implementations MUST NOT throw on the
310
+ * absent case; transport failures still throw.
311
+ *
312
+ * Hard delete is the registry's established author-key removal
313
+ * semantic: the durable audit trail is the public key pinned per
314
+ * published version (`ArtifactVersionRow.authorPublicKey` +
315
+ * `publishedBy`), which this delete never touches — removal only
316
+ * blocks FUTURE publishes signed with the key.
317
+ */
318
+ deleteAuthorKey(subject: string, keyId: string): Promise<boolean>;
214
319
  }
215
320
  //# sourceMappingURL=registry-storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry-storage.d.ts","sourceRoot":"","sources":["../../src/interfaces/registry-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAQ3C;AAED,MAAM,WAAW,eAAe;IAE9B,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IAC9E,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D;;;;;;;;;;OAUG;IACH,aAAa,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC;QACjD,QAAQ,CAAC,IAAI,EAAE,SAAS,oBAAoB,EAAE,CAAC;QAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC,CAAC;IAGH,kBAAkB,CAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;IACtC;;;;;;;;;;;;;;;;;OAiBG;IACH,oBAAoB,CAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;IAC1C;;;;;OAKG;IACH,0BAA0B,CACxB,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,gBAAgB,CAAA;KAAE,CAAC,CAAC;IACnE,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGxE;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACH,oBAAoB,CAClB,UAAU,EAAE,kBAAkB,EAC9B,OAAO,EAAE,eAAe,GACvB,OAAO,CACN;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAA;KAAE,GACxC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,gBAAgB,CAAA;KAAE,CAC1C,CAAC;IAGF,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAC3E;;;;;;OAMG;IACH,YAAY,CACV,GAAG,EAAE,YAAY,EACjB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;CACnE"}
1
+ {"version":3,"file":"registry-storage.d.ts","sourceRoot":"","sources":["../../src/interfaces/registry-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared MCP-tool search-filter predicate — the reference semantics
3
+ * every {@link RegistryStorage.scanArtifacts} implementation must
4
+ * reproduce for the `tool` / `server` filter dimensions:
5
+ *
6
+ * - `tool` only → any binding entry with that tool name (with or
7
+ * without a `server`).
8
+ * - `server` only → any binding entry declaring that server; bare
9
+ * (server-less) entries never match.
10
+ * - both → a single entry with exactly that (server, tool)
11
+ * pair.
12
+ * - neither → always `true` (the filter is inactive).
13
+ *
14
+ * Matching is case-sensitive exact on both dimensions — MCP tool names
15
+ * are case-sensitive. AND-composes with every other scan-filter
16
+ * dimension; artifacts without bindings never match an active filter.
17
+ */
18
+ import type { McpToolBinding } from '@ggui-ai/artifact-manifest';
19
+ export declare function matchesMcpToolFilters(bindings: ReadonlyArray<McpToolBinding> | undefined, filters: {
20
+ tool?: string;
21
+ server?: string;
22
+ }): boolean;
23
+ //# sourceMappingURL=mcp-tool-filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tool-filters.d.ts","sourceRoot":"","sources":["../src/mcp-tool-filters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,GAAG,SAAS,EACnD,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1C,OAAO,CAST"}