@ggui-ai/registry-core 0.1.0-rc.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/LICENSE +201 -0
- package/README.md +76 -0
- package/dist/impls/memory-bundle-storage.d.ts +12 -0
- package/dist/impls/memory-bundle-storage.d.ts.map +1 -0
- package/dist/impls/memory-bundle-storage.js +40 -0
- package/dist/impls/memory-registry-storage.d.ts +3 -0
- package/dist/impls/memory-registry-storage.d.ts.map +1 -0
- package/dist/impls/memory-registry-storage.js +154 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/interfaces/authn.d.ts +51 -0
- package/dist/interfaces/authn.d.ts.map +1 -0
- package/dist/interfaces/authn.js +1 -0
- package/dist/interfaces/bundle-storage.d.ts +79 -0
- package/dist/interfaces/bundle-storage.d.ts.map +1 -0
- package/dist/interfaces/bundle-storage.js +1 -0
- package/dist/interfaces/registry-storage.d.ts +204 -0
- package/dist/interfaces/registry-storage.d.ts.map +1 -0
- package/dist/interfaces/registry-storage.js +19 -0
- package/dist/ops/compile.d.ts +48 -0
- package/dist/ops/compile.d.ts.map +1 -0
- package/dist/ops/compile.js +163 -0
- package/dist/ops/conformance.d.ts +154 -0
- package/dist/ops/conformance.d.ts.map +1 -0
- package/dist/ops/conformance.js +487 -0
- package/dist/ops/list-versions.d.ts +58 -0
- package/dist/ops/list-versions.d.ts.map +1 -0
- package/dist/ops/list-versions.js +60 -0
- package/dist/ops/publish.d.ts +70 -0
- package/dist/ops/publish.d.ts.map +1 -0
- package/dist/ops/publish.js +417 -0
- package/dist/ops/read.d.ts +52 -0
- package/dist/ops/read.d.ts.map +1 -0
- package/dist/ops/read.js +60 -0
- package/dist/ops/register-author-key.d.ts +22 -0
- package/dist/ops/register-author-key.d.ts.map +1 -0
- package/dist/ops/register-author-key.js +171 -0
- package/dist/ops/search.d.ts +50 -0
- package/dist/ops/search.d.ts.map +1 -0
- package/dist/ops/search.js +106 -0
- package/dist/testing/bundle-storage-contract.d.ts +3 -0
- package/dist/testing/bundle-storage-contract.d.ts.map +1 -0
- package/dist/testing/bundle-storage-contract.js +176 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +9 -0
- package/dist/testing/registry-storage-contract.d.ts +3 -0
- package/dist/testing/registry-storage-contract.d.ts.map +1 -0
- package/dist/testing/registry-storage-contract.js +392 -0
- package/dist/types.d.ts +482 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +110 -0
- package/dist/utils/base64.d.ts +15 -0
- package/dist/utils/base64.d.ts.map +1 -0
- package/dist/utils/base64.js +35 -0
- package/dist/utils/semver.d.ts +13 -0
- package/dist/utils/semver.d.ts.map +1 -0
- package/dist/utils/semver.js +69 -0
- package/package.json +85 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row + wire shapes for the ggui marketplace registry. The same
|
|
3
|
+
* shapes back both this open-source server and the hosted registry,
|
|
4
|
+
* so they project against one definition.
|
|
5
|
+
*
|
|
6
|
+
* Rows are the storage-layer projection — what {@link RegistryStorage}
|
|
7
|
+
* implementations read/write. Wire shapes are the public HTTP response
|
|
8
|
+
* surface — what the registry exposes to CLI clients. The two are
|
|
9
|
+
* deliberately separate: the row carries fields the wire never emits
|
|
10
|
+
* (`yanked`, `sk`) and the wire flattens fields the row stores nested.
|
|
11
|
+
*
|
|
12
|
+
* The umbrella noun is `artifact` — the registry stores BOTH gadgets
|
|
13
|
+
* AND blueprints under one row family, with `kind: 'gadget' |
|
|
14
|
+
* 'blueprint'` as the discriminator. The field name `artifactId`
|
|
15
|
+
* matches what the field actually contains.
|
|
16
|
+
*/
|
|
17
|
+
import type { ArtifactManifest } from '@ggui-ai/artifact-manifest';
|
|
18
|
+
import type { GadgetSignature } from '@ggui-ai/gadget-signing';
|
|
19
|
+
import type { ConformanceFailureCode } from './ops/conformance.js';
|
|
20
|
+
/**
|
|
21
|
+
* SK literal for the per-artifactId metadata row on the cloud's
|
|
22
|
+
* Artifacts table. Pinned as a constant so cloud + OSS impls agree
|
|
23
|
+
* on the SK.
|
|
24
|
+
*
|
|
25
|
+
* OSS impls (filesystem / memory) MAY ignore this — they have one row
|
|
26
|
+
* per artifactId so no SK is needed. Cloud DDB impls MUST honor it.
|
|
27
|
+
*/
|
|
28
|
+
export declare const ARTIFACTS_METADATA_SK: "metadata#";
|
|
29
|
+
/**
|
|
30
|
+
* Visibility — public artifacts are sigstore-signed + listable; private
|
|
31
|
+
* artifacts are Ed25519-signed + scoped to the publisher org. Matches
|
|
32
|
+
* `ArtifactVisibilitySchema` in `@ggui-ai/artifact-manifest`.
|
|
33
|
+
*/
|
|
34
|
+
export type Visibility = 'public' | 'private';
|
|
35
|
+
/**
|
|
36
|
+
* Artifact discriminator. Matches `kind` on every artifact manifest.
|
|
37
|
+
*/
|
|
38
|
+
export type ArtifactKind = 'gadget' | 'blueprint';
|
|
39
|
+
/**
|
|
40
|
+
* Per-artifactId metadata row. One row per `<scope>/<name>`, regardless
|
|
41
|
+
* of how many versions exist. Updated on every publish to point at the
|
|
42
|
+
* new latest. `/search` scans only this row family — versions-table
|
|
43
|
+
* scans would explode the search domain.
|
|
44
|
+
*
|
|
45
|
+
* `artifactId` is the umbrella noun: the registry stores gadgets +
|
|
46
|
+
* blueprints under one row family, and `kind` distinguishes them.
|
|
47
|
+
*/
|
|
48
|
+
export interface ArtifactsMetadataRow {
|
|
49
|
+
readonly artifactId: string;
|
|
50
|
+
readonly sk: typeof ARTIFACTS_METADATA_SK;
|
|
51
|
+
readonly kind: ArtifactKind;
|
|
52
|
+
readonly latestVersion: string;
|
|
53
|
+
readonly description?: string;
|
|
54
|
+
readonly tags?: readonly string[];
|
|
55
|
+
readonly visibility: Visibility;
|
|
56
|
+
readonly hook?: string;
|
|
57
|
+
readonly authorName?: string;
|
|
58
|
+
readonly publishedAt: string;
|
|
59
|
+
readonly publishedBy: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Per-version row. One row per published version. The manifest is
|
|
63
|
+
* stored verbatim (post-parse) plus the fetchable URLs + signing
|
|
64
|
+
* metadata. Yanks set `yanked: true` — the row stays so the URL keeps
|
|
65
|
+
* resolving with a 410 for audit. Hard-delete is intentionally NOT
|
|
66
|
+
* supported at MVP.
|
|
67
|
+
*
|
|
68
|
+
* Blueprint versions point at a {@link CompiledBlobRow} via
|
|
69
|
+
* `compiledDigest`. The blob row carries the compiled JS bytes
|
|
70
|
+
* (esbuild output) keyed by `sha256(compiledBytes)`. Raw TSX is
|
|
71
|
+
* preserved on `manifest.source` for audit / future-recompile;
|
|
72
|
+
* compiled JS lives only in the blob layer. Two-layer storage gives
|
|
73
|
+
* dedup (same TSX → same digest → single blob row) and federation-
|
|
74
|
+
* ready content-addressable identity.
|
|
75
|
+
*/
|
|
76
|
+
export interface ArtifactVersionRow {
|
|
77
|
+
readonly artifactId: string;
|
|
78
|
+
readonly version: string;
|
|
79
|
+
readonly manifest: ArtifactManifest;
|
|
80
|
+
readonly kind: ArtifactKind;
|
|
81
|
+
readonly visibility: Visibility;
|
|
82
|
+
readonly bundleUrl?: string;
|
|
83
|
+
readonly bundleSri?: string;
|
|
84
|
+
readonly signatureUrl?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Pointer into the {@link CompiledBlobRow} table. Set on blueprint
|
|
87
|
+
* publish; absent on gadget rows (gadgets ship via `bundleUrl`).
|
|
88
|
+
* Hex-encoded SHA-256 of the compiled JS bytes.
|
|
89
|
+
*
|
|
90
|
+
* Resolution invariant: a non-null `compiledDigest` on a published
|
|
91
|
+
* blueprint row MUST resolve to a {@link CompiledBlobRow} via
|
|
92
|
+
* {@link RegistryStorage.getCompiledBlob}. A missing blob row when
|
|
93
|
+
* the pointer is set is a CRITICAL storage-layer inconsistency —
|
|
94
|
+
* `fetchAndVerifyBlueprint` (cloud) and `runArtifactInstall` (OSS)
|
|
95
|
+
* raise immediately rather than fall back.
|
|
96
|
+
*/
|
|
97
|
+
readonly compiledDigest?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Base64-encoded raw Ed25519 public key bytes (32 bytes). Pinned at
|
|
100
|
+
* publish time so a subsequent key rotation in {@link AuthorKeyRow}
|
|
101
|
+
* does NOT invalidate historical versions.
|
|
102
|
+
*/
|
|
103
|
+
readonly authorPublicKey?: string;
|
|
104
|
+
readonly publishedAt: string;
|
|
105
|
+
readonly publishedBy: string;
|
|
106
|
+
readonly yanked?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Content-addressed compiled-bytes row — the storage layer for a
|
|
110
|
+
* blueprint's compiled JS (esbuild output of its TSX source).
|
|
111
|
+
*
|
|
112
|
+
* Stored in a separate table keyed by `compiledDigest = sha256(bytes)`.
|
|
113
|
+
* Multiple {@link ArtifactVersionRow} entries can point at the SAME
|
|
114
|
+
* `compiledDigest` — two publishes of byte-identical compiled output
|
|
115
|
+
* dedup to one blob row with `refCount` tracking pointer count. The
|
|
116
|
+
* deterministic-compile contract (`compile(source) → sha256(bytes)`
|
|
117
|
+
* is a pure function pinned to a frozen esbuild config) makes dedup
|
|
118
|
+
* load-bearing: federation-ready, cross-app cache sharing, and
|
|
119
|
+
* sigstore signing all key off `compiledDigest`.
|
|
120
|
+
*
|
|
121
|
+
* **Storage choice — inline base64 vs S3 pointer.** The compiled
|
|
122
|
+
* bytes are inlined as a base64-encoded string column. Rationale:
|
|
123
|
+
* blueprints today ship raw TSX inline on `manifest.source` (capped
|
|
124
|
+
* at 5 MiB by `MAX_BLUEPRINT_SOURCE_BYTES`); compiled JS is typically
|
|
125
|
+
* 1.5–3× the TSX size. DynamoDB's 400-KiB item ceiling caps practical
|
|
126
|
+
* inline storage around ~300 KiB compiled (~200 KiB TSX), which
|
|
127
|
+
* accommodates every realistic blueprint observed so far. Larger
|
|
128
|
+
* blueprints (and gadgets, which always exceed this) will need an
|
|
129
|
+
* S3-pointer variant as a future enhancement. Inline storage keeps
|
|
130
|
+
* the two-layer write/read contract simple, without the bucket-
|
|
131
|
+
* lifecycle and IAM-grant overhead of S3.
|
|
132
|
+
*
|
|
133
|
+
* **GC.** `refCount` is maintained on publish (+1) and yank (no
|
|
134
|
+
* decrement — yanked versions retain their pointer for audit;
|
|
135
|
+
* permanent delete would decrement). A dedicated reaper is a future
|
|
136
|
+
* enhancement; the column is reserved so it can land later without a
|
|
137
|
+
* row migration. Today no row ever drops to `refCount=0`, so the
|
|
138
|
+
* absence of a reaper is observable only via storage growth.
|
|
139
|
+
*
|
|
140
|
+
* **Signatures.** `manifestSig` is the publisher's signature
|
|
141
|
+
* (Ed25519 for private artifacts, sigstore-cosign for public) over
|
|
142
|
+
* the manifest's canonical-JSON projection — read by the hosted
|
|
143
|
+
* install path for defense-in-depth re-verification. Stored as a
|
|
144
|
+
* JSON-encoded `GadgetSignature` discriminated union. `compiledSig`
|
|
145
|
+
* (a registry-rooted sigstore signature over `compiledBytes`) is
|
|
146
|
+
* reserved for a future enhancement.
|
|
147
|
+
*/
|
|
148
|
+
export interface CompiledBlobRow {
|
|
149
|
+
/** PK. Lowercase hex SHA-256 of `compiledBytes` (64 chars). */
|
|
150
|
+
readonly compiledDigest: string;
|
|
151
|
+
/** Base64-encoded compiled JS bytes (esbuild output). */
|
|
152
|
+
readonly compiledBytes: string;
|
|
153
|
+
/** Decoded byte length — convenience for size checks without re-decoding. */
|
|
154
|
+
readonly compiledSize: number;
|
|
155
|
+
/**
|
|
156
|
+
* Pointer count from {@link ArtifactVersionRow.compiledDigest}.
|
|
157
|
+
* Maintained on publish; reserved for a future GC reaper.
|
|
158
|
+
*/
|
|
159
|
+
readonly refCount: number;
|
|
160
|
+
/**
|
|
161
|
+
* Publisher's signature envelope, JSON-encoded `GadgetSignature`
|
|
162
|
+
* discriminated union (Ed25519 for private, sigstore-cosign for
|
|
163
|
+
* public). Read by the hosted install path for defense-in-depth
|
|
164
|
+
* re-verification before persisting an installed blueprint. May be
|
|
165
|
+
* absent on rows published before signature persistence existed;
|
|
166
|
+
* the install path hard-fails such rows with a clear error pointing
|
|
167
|
+
* at this column.
|
|
168
|
+
*/
|
|
169
|
+
readonly manifestSig?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Reserved — a registry-rooted sigstore signature over
|
|
172
|
+
* `compiledBytes`, planned for a future enhancement. When shipped,
|
|
173
|
+
* the install-time verifier's full anchor is:
|
|
174
|
+
* `verify(manifestSig, manifest) AND verify(compiledSig, bytes) AND
|
|
175
|
+
* sha256(bytes) === compiledDigest`.
|
|
176
|
+
*/
|
|
177
|
+
readonly compiledSig?: string;
|
|
178
|
+
/** ISO timestamp set on first-write of the blob row. */
|
|
179
|
+
readonly createdAt: string;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Author signing-key row. One per `(subject, keyId)` pair. The key is
|
|
183
|
+
* stored base64 — verification re-decodes + invokes
|
|
184
|
+
* {@link verifyBundleEd25519}.
|
|
185
|
+
*/
|
|
186
|
+
export interface AuthorKeyRow {
|
|
187
|
+
readonly subject: string;
|
|
188
|
+
readonly keyId: string;
|
|
189
|
+
readonly publicKeyBase64: string;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* `GET /pkg/{scope}/{name}/{version}` body.
|
|
193
|
+
*
|
|
194
|
+
* `manifest` is always present (even on 410 Gone — yanked versions
|
|
195
|
+
* still return the manifest for audit). `bundleUrl` / `bundleSri` /
|
|
196
|
+
* `signatureUrl` are gadget-only.
|
|
197
|
+
*
|
|
198
|
+
* Blueprints expose their canonical compiled JS bytes via
|
|
199
|
+
* `compiledBytes` (base64) + `compiledDigest` (hex SHA-256). The raw
|
|
200
|
+
* TSX is on `manifest.source` for audit / recompile; install paths
|
|
201
|
+
* MUST use `compiledBytes` — the registry is the trust boundary for
|
|
202
|
+
* the compile step. `compiledDigest` doubles as the cache key for
|
|
203
|
+
* cross-app sharing and federation.
|
|
204
|
+
*/
|
|
205
|
+
export interface ReadPkgResponse {
|
|
206
|
+
readonly manifest: ArtifactManifest;
|
|
207
|
+
readonly bundleUrl?: string;
|
|
208
|
+
readonly bundleSri?: string;
|
|
209
|
+
readonly signatureUrl?: string;
|
|
210
|
+
/** Hex SHA-256 of the compiled bytes — present on blueprint reads. */
|
|
211
|
+
readonly compiledDigest?: string;
|
|
212
|
+
/** Base64 compiled JS bytes — present on blueprint reads. */
|
|
213
|
+
readonly compiledBytes?: string;
|
|
214
|
+
readonly authorPublicKey?: string;
|
|
215
|
+
readonly publishedAt: string;
|
|
216
|
+
readonly publishedBy: string;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* One row of `GET /search?…` results — a lightweight per-artifactId
|
|
220
|
+
* summary intentionally narrower than the full read response so the
|
|
221
|
+
* CLI list view stays cheap.
|
|
222
|
+
*/
|
|
223
|
+
export interface SearchResultEntry {
|
|
224
|
+
readonly artifactId: string;
|
|
225
|
+
readonly latestVersion: string;
|
|
226
|
+
readonly kind: ArtifactKind;
|
|
227
|
+
readonly description?: string;
|
|
228
|
+
readonly tags?: readonly string[];
|
|
229
|
+
readonly publishedAt: string;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* `GET /search?…` body. `nextCursor` is opaque (impl-defined: cloud
|
|
233
|
+
* uses base64-encoded DDB LastEvaluatedKey; OSS uses an offset). Clients
|
|
234
|
+
* roundtrip it verbatim on the next call.
|
|
235
|
+
*/
|
|
236
|
+
export interface SearchResponse {
|
|
237
|
+
readonly results: readonly SearchResultEntry[];
|
|
238
|
+
readonly nextCursor?: string;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* `GET /search` sort options. Supports a registry-web "Recent" view
|
|
242
|
+
* that needs `publishedAt`-DESC ordering.
|
|
243
|
+
*
|
|
244
|
+
* - `recent` — order by {@link ArtifactsMetadataRow.publishedAt} DESC.
|
|
245
|
+
*
|
|
246
|
+
* Default (sort omitted) is impl-defined ordering: memory uses insertion
|
|
247
|
+
* order, filesystem uses directory order, DDB uses Scan order. Callers
|
|
248
|
+
* MUST opt in to a deterministic order via this field.
|
|
249
|
+
*
|
|
250
|
+
* **Scale ceiling.** The `recent` sort is implemented as an in-memory
|
|
251
|
+
* pass on the page returned by {@link RegistryStorage.scanArtifacts}.
|
|
252
|
+
* For pre-launch row counts (< ~1k artifacts, single-page scans with
|
|
253
|
+
* `limit=200`) this gives a globally-correct order. Once the artifact
|
|
254
|
+
* table grows past one Scan page (~1 MiB of items), the order is only
|
|
255
|
+
* page-local — clients paginating with `cursor` see per-page recency,
|
|
256
|
+
* not global. A DDB GSI on `publishedAt` is the proper fix and is
|
|
257
|
+
* planned as a follow-up.
|
|
258
|
+
*/
|
|
259
|
+
export declare const SEARCH_SORT_OPTIONS: readonly ["recent"];
|
|
260
|
+
export type SearchSort = (typeof SEARCH_SORT_OPTIONS)[number];
|
|
261
|
+
/**
|
|
262
|
+
* One row of `GET /pkg/{scope}/{name}` list-versions results — backs
|
|
263
|
+
* a package detail page's version timeline. Lightweight by design:
|
|
264
|
+
* drops manifest, compiledDigest, manifestSig, etc. — clients hit
|
|
265
|
+
* `/pkg/.../:version` for the full row.
|
|
266
|
+
*
|
|
267
|
+
* - `version` — the semver string. UNIQUE per (artifactId, version).
|
|
268
|
+
* - `publishedAt` — ISO timestamp of the original publish.
|
|
269
|
+
* - `yanked` — true ⇔ the version row carries `yanked: true`. UI
|
|
270
|
+
* should render yanked rows with a strikethrough +
|
|
271
|
+
* warning rather than hide them.
|
|
272
|
+
* - `kind` — gadget | blueprint (matches the metadata row's
|
|
273
|
+
* kind; carried per-version so cross-version kind
|
|
274
|
+
* drift would surface in the UI).
|
|
275
|
+
* - `visibility` — public | private. Private rows are filtered out
|
|
276
|
+
* for unauthenticated callers at the op layer.
|
|
277
|
+
*/
|
|
278
|
+
export interface VersionListEntry {
|
|
279
|
+
readonly version: string;
|
|
280
|
+
readonly publishedAt: string;
|
|
281
|
+
readonly yanked: boolean;
|
|
282
|
+
readonly kind: ArtifactKind;
|
|
283
|
+
readonly visibility: Visibility;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* `GET /pkg/{scope}/{name}` body.
|
|
287
|
+
*
|
|
288
|
+
* - `artifactId` — echoed so a single-row consumer doesn't have to
|
|
289
|
+
* reconstruct from URL params.
|
|
290
|
+
* - `versions` — semver-DESC list of {@link VersionListEntry}.
|
|
291
|
+
* Latest first.
|
|
292
|
+
*
|
|
293
|
+
* No pagination cursor — registry artifact version counts are
|
|
294
|
+
* inherently bounded (typical: < 50 versions per artifact, hard ceiling
|
|
295
|
+
* around ~1k for the lifetime of an artifact). If a single artifact ever
|
|
296
|
+
* crosses the 1 MiB DDB Query page, we'll add a cursor — but for now the
|
|
297
|
+
* round-trip cost of paginating versions is greater than the cost of
|
|
298
|
+
* returning them all.
|
|
299
|
+
*/
|
|
300
|
+
export interface ListVersionsResponse {
|
|
301
|
+
readonly artifactId: string;
|
|
302
|
+
readonly versions: readonly VersionListEntry[];
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* `POST /publish` request body.
|
|
306
|
+
*/
|
|
307
|
+
export interface PublishRequestBody {
|
|
308
|
+
readonly manifest: unknown;
|
|
309
|
+
readonly bundle?: string;
|
|
310
|
+
readonly bundleSha384?: string;
|
|
311
|
+
readonly signature: GadgetSignature;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 201 response on a successful publish. `installCommand` is the exact
|
|
315
|
+
* shell command to install the artifact — the registry hostname is
|
|
316
|
+
* threaded through {@link PublishArtifactDeps.registryHostname}
|
|
317
|
+
* so each deployment issues an environment-appropriate command.
|
|
318
|
+
*/
|
|
319
|
+
export interface PublishResponseBody {
|
|
320
|
+
readonly artifactId: string;
|
|
321
|
+
readonly version: string;
|
|
322
|
+
readonly manifestUrl: string;
|
|
323
|
+
readonly bundleUrl?: string;
|
|
324
|
+
readonly signatureUrl?: string;
|
|
325
|
+
readonly installCommand: string;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Locked publish error codes. Strings are the wire contract — the
|
|
329
|
+
* publish CLI matches on these for human-readable rendering. The
|
|
330
|
+
* `as const` tuple is the value-level source of truth; the
|
|
331
|
+
* {@link PublishErrorCode} type is derived from it so a single edit
|
|
332
|
+
* propagates to both the wire and the runtime membership check used
|
|
333
|
+
* by downstream guards.
|
|
334
|
+
*/
|
|
335
|
+
export declare const PUBLISH_ERROR_CODES: readonly ["unauthorized", "manifest_invalid", "bundle_required", "bundle_too_large", "conformance_failed", "bundle_hash_mismatch", "unknown_key", "signature_invalid", "version_exists", "internal"];
|
|
336
|
+
export type PublishErrorCode = (typeof PUBLISH_ERROR_CODES)[number];
|
|
337
|
+
/**
|
|
338
|
+
* Closed enum for `GET /pkg/:scope/:name[/version]` read responses.
|
|
339
|
+
*
|
|
340
|
+
* `yanked` is the 410-Gone path — the version exists in metadata but
|
|
341
|
+
* the publisher revoked it. Clients SHOULD treat this as a hard
|
|
342
|
+
* failure (don't fall back to a different version automatically).
|
|
343
|
+
*/
|
|
344
|
+
export declare const READ_ERROR_CODES: readonly ["not_found", "forbidden", "invalid_request", "yanked", "server_error"];
|
|
345
|
+
export type ReadErrorCode = (typeof READ_ERROR_CODES)[number];
|
|
346
|
+
/**
|
|
347
|
+
* Closed enum for `GET /search` responses. Same posture as
|
|
348
|
+
* {@link ReadErrorCode} minus the `yanked` path (search filters
|
|
349
|
+
* yanked rows out of the result set; it never surfaces as a top-level
|
|
350
|
+
* error).
|
|
351
|
+
*/
|
|
352
|
+
export declare const SEARCH_ERROR_CODES: readonly ["forbidden", "invalid_request", "server_error"];
|
|
353
|
+
export type SearchErrorCode = (typeof SEARCH_ERROR_CODES)[number];
|
|
354
|
+
/**
|
|
355
|
+
* Closed enum for `POST /author-keys` register responses. An operator
|
|
356
|
+
* registers a per-scope Ed25519 public key with the registry so
|
|
357
|
+
* future `POST /publish` calls signed by the matching private key
|
|
358
|
+
* validate against an `AuthorKeyRow`.
|
|
359
|
+
*
|
|
360
|
+
* - `unauthorized` — missing or invalid caller credentials.
|
|
361
|
+
* - `invalid_request` — body missing `publicKeyBase64`, malformed
|
|
362
|
+
* base64, or wrong byte length.
|
|
363
|
+
* - `key_conflict` — a row already exists for `(subject, keyId)`
|
|
364
|
+
* with a different `publicKeyBase64`. Same
|
|
365
|
+
* publicKey is treated as idempotent → 200.
|
|
366
|
+
* - `server_error` — unexpected adapter failure.
|
|
367
|
+
*/
|
|
368
|
+
export declare const REGISTER_AUTHOR_KEY_ERROR_CODES: readonly ["unauthorized", "invalid_request", "key_conflict", "server_error"];
|
|
369
|
+
export type RegisterAuthorKeyErrorCode = (typeof REGISTER_AUTHOR_KEY_ERROR_CODES)[number];
|
|
370
|
+
/**
|
|
371
|
+
* `POST /author-keys` request body. The subject is derived from the
|
|
372
|
+
* verified caller credentials (not the body) — the operator can only
|
|
373
|
+
* register keys under their own identity. `keyId` is derived
|
|
374
|
+
* deterministically from
|
|
375
|
+
* the public key bytes via `derivePublicKeyId` (gadget-signing) — not
|
|
376
|
+
* caller-supplied — so two clients registering the same public key
|
|
377
|
+
* produce the same row.
|
|
378
|
+
*/
|
|
379
|
+
export interface RegisterAuthorKeyRequestBody {
|
|
380
|
+
readonly publicKeyBase64: string;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* `POST /author-keys` 200/201 response. Echoes the stored row so the
|
|
384
|
+
* CLI can confirm the (subject, keyId) tuple the registry now knows.
|
|
385
|
+
* 201 on first-write; 200 on idempotent re-register of the same row.
|
|
386
|
+
*/
|
|
387
|
+
export interface RegisterAuthorKeyResponseBody {
|
|
388
|
+
readonly subject: string;
|
|
389
|
+
readonly keyId: string;
|
|
390
|
+
readonly publicKeyBase64: string;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* `POST /author-keys` error body — same shape as the read/search
|
|
394
|
+
* error bodies; `error` is narrowed to the closed enum.
|
|
395
|
+
*/
|
|
396
|
+
export interface RegisterAuthorKeyErrorBody {
|
|
397
|
+
readonly error: RegisterAuthorKeyErrorCode;
|
|
398
|
+
readonly message: string;
|
|
399
|
+
readonly detail?: unknown;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Publish-endpoint error body. `error` is narrowed to
|
|
403
|
+
* {@link PublishErrorCode} so consumers get autocomplete +
|
|
404
|
+
* exhaustiveness; `conformanceFailureCode` is hoisted to the TOP of
|
|
405
|
+
* the body (alongside `error: 'conformance_failed'`) so callers can
|
|
406
|
+
* branch without parsing nested JSON. The full per-error list stays
|
|
407
|
+
* in `detail.errors` for verbose rendering.
|
|
408
|
+
*/
|
|
409
|
+
export interface PublishErrorBody {
|
|
410
|
+
readonly error: PublishErrorCode;
|
|
411
|
+
readonly message: string;
|
|
412
|
+
/**
|
|
413
|
+
* Sub-discriminator for `error: 'conformance_failed'` — the code of
|
|
414
|
+
* the FIRST conformance failure (the list is in `detail.errors`).
|
|
415
|
+
* Omitted for every other `error` value.
|
|
416
|
+
*/
|
|
417
|
+
readonly conformanceFailureCode?: ConformanceFailureCode;
|
|
418
|
+
readonly detail?: unknown;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Read-endpoint error body. `error` narrowed to {@link ReadErrorCode}.
|
|
422
|
+
*/
|
|
423
|
+
export interface ReadErrorBody {
|
|
424
|
+
readonly error: ReadErrorCode;
|
|
425
|
+
readonly message: string;
|
|
426
|
+
readonly detail?: unknown;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Search-endpoint error body. `error` narrowed to {@link SearchErrorCode}.
|
|
430
|
+
*/
|
|
431
|
+
export interface SearchErrorBody {
|
|
432
|
+
readonly error: SearchErrorCode;
|
|
433
|
+
readonly message: string;
|
|
434
|
+
readonly detail?: unknown;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Discriminated union of every registry error body. Use the
|
|
438
|
+
* per-endpoint shapes ({@link PublishErrorBody} / {@link ReadErrorBody}
|
|
439
|
+
* / {@link SearchErrorBody}) at op + handler seams; this union exists
|
|
440
|
+
* for callers that touch more than one endpoint (e.g. a transport-layer
|
|
441
|
+
* logger).
|
|
442
|
+
*/
|
|
443
|
+
export type ErrorBody = PublishErrorBody | ReadErrorBody | SearchErrorBody | RegisterAuthorKeyErrorBody | ListVersionsErrorBody;
|
|
444
|
+
/**
|
|
445
|
+
* Search filter shape. Passed to {@link RegistryStorage.scanArtifacts}.
|
|
446
|
+
* `limit` is clamped to [1, 200] by {@link searchArtifacts}; impls
|
|
447
|
+
* should respect it as a hard ceiling. `cursor` is opaque to consumers
|
|
448
|
+
* — impls choose their own encoding (DDB LastEvaluatedKey base64;
|
|
449
|
+
* memory uses an integer offset; filesystem uses a last-seen artifactId).
|
|
450
|
+
*/
|
|
451
|
+
export interface ArtifactScanFilter {
|
|
452
|
+
readonly q?: string;
|
|
453
|
+
readonly kind?: ArtifactKind;
|
|
454
|
+
readonly hook?: string;
|
|
455
|
+
readonly tag?: string;
|
|
456
|
+
readonly author?: string;
|
|
457
|
+
readonly limit?: number;
|
|
458
|
+
readonly cursor?: string;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Closed enum for `GET /pkg/{scope}/{name}` list-versions responses.
|
|
462
|
+
*
|
|
463
|
+
* - `invalid_request` — missing or malformed `artifactId`.
|
|
464
|
+
* - `not_found` — no metadata row for `artifactId`. Distinct
|
|
465
|
+
* from "metadata present but every version is
|
|
466
|
+
* private + caller unauthed" (that path returns
|
|
467
|
+
* 200 with `versions: []` — exposing 404 vs
|
|
468
|
+
* empty would leak private-row existence).
|
|
469
|
+
* - `server_error` — unexpected adapter failure.
|
|
470
|
+
*/
|
|
471
|
+
export declare const LIST_VERSIONS_ERROR_CODES: readonly ["invalid_request", "not_found", "server_error"];
|
|
472
|
+
export type ListVersionsErrorCode = (typeof LIST_VERSIONS_ERROR_CODES)[number];
|
|
473
|
+
/**
|
|
474
|
+
* List-versions error body. `error` narrowed to {@link ListVersionsErrorCode}.
|
|
475
|
+
* Mirrors {@link ReadErrorBody}'s shape so callers can share a renderer.
|
|
476
|
+
*/
|
|
477
|
+
export interface ListVersionsErrorBody {
|
|
478
|
+
readonly error: ListVersionsErrorCode;
|
|
479
|
+
readonly message: string;
|
|
480
|
+
readonly detail?: unknown;
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SK literal for the per-artifactId metadata row on the cloud's
|
|
3
|
+
* Artifacts table. Pinned as a constant so cloud + OSS impls agree
|
|
4
|
+
* on the SK.
|
|
5
|
+
*
|
|
6
|
+
* OSS impls (filesystem / memory) MAY ignore this — they have one row
|
|
7
|
+
* per artifactId so no SK is needed. Cloud DDB impls MUST honor it.
|
|
8
|
+
*/
|
|
9
|
+
export const ARTIFACTS_METADATA_SK = 'metadata#';
|
|
10
|
+
/**
|
|
11
|
+
* `GET /search` sort options. Supports a registry-web "Recent" view
|
|
12
|
+
* that needs `publishedAt`-DESC ordering.
|
|
13
|
+
*
|
|
14
|
+
* - `recent` — order by {@link ArtifactsMetadataRow.publishedAt} DESC.
|
|
15
|
+
*
|
|
16
|
+
* Default (sort omitted) is impl-defined ordering: memory uses insertion
|
|
17
|
+
* order, filesystem uses directory order, DDB uses Scan order. Callers
|
|
18
|
+
* MUST opt in to a deterministic order via this field.
|
|
19
|
+
*
|
|
20
|
+
* **Scale ceiling.** The `recent` sort is implemented as an in-memory
|
|
21
|
+
* pass on the page returned by {@link RegistryStorage.scanArtifacts}.
|
|
22
|
+
* For pre-launch row counts (< ~1k artifacts, single-page scans with
|
|
23
|
+
* `limit=200`) this gives a globally-correct order. Once the artifact
|
|
24
|
+
* table grows past one Scan page (~1 MiB of items), the order is only
|
|
25
|
+
* page-local — clients paginating with `cursor` see per-page recency,
|
|
26
|
+
* not global. A DDB GSI on `publishedAt` is the proper fix and is
|
|
27
|
+
* planned as a follow-up.
|
|
28
|
+
*/
|
|
29
|
+
export const SEARCH_SORT_OPTIONS = ['recent'];
|
|
30
|
+
/**
|
|
31
|
+
* Locked publish error codes. Strings are the wire contract — the
|
|
32
|
+
* publish CLI matches on these for human-readable rendering. The
|
|
33
|
+
* `as const` tuple is the value-level source of truth; the
|
|
34
|
+
* {@link PublishErrorCode} type is derived from it so a single edit
|
|
35
|
+
* propagates to both the wire and the runtime membership check used
|
|
36
|
+
* by downstream guards.
|
|
37
|
+
*/
|
|
38
|
+
export const PUBLISH_ERROR_CODES = [
|
|
39
|
+
'unauthorized',
|
|
40
|
+
'manifest_invalid',
|
|
41
|
+
'bundle_required',
|
|
42
|
+
'bundle_too_large',
|
|
43
|
+
'conformance_failed',
|
|
44
|
+
'bundle_hash_mismatch',
|
|
45
|
+
'unknown_key',
|
|
46
|
+
'signature_invalid',
|
|
47
|
+
'version_exists',
|
|
48
|
+
'internal',
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Closed enum for `GET /pkg/:scope/:name[/version]` read responses.
|
|
52
|
+
*
|
|
53
|
+
* `yanked` is the 410-Gone path — the version exists in metadata but
|
|
54
|
+
* the publisher revoked it. Clients SHOULD treat this as a hard
|
|
55
|
+
* failure (don't fall back to a different version automatically).
|
|
56
|
+
*/
|
|
57
|
+
export const READ_ERROR_CODES = [
|
|
58
|
+
'not_found',
|
|
59
|
+
'forbidden',
|
|
60
|
+
'invalid_request',
|
|
61
|
+
'yanked',
|
|
62
|
+
'server_error',
|
|
63
|
+
];
|
|
64
|
+
/**
|
|
65
|
+
* Closed enum for `GET /search` responses. Same posture as
|
|
66
|
+
* {@link ReadErrorCode} minus the `yanked` path (search filters
|
|
67
|
+
* yanked rows out of the result set; it never surfaces as a top-level
|
|
68
|
+
* error).
|
|
69
|
+
*/
|
|
70
|
+
export const SEARCH_ERROR_CODES = [
|
|
71
|
+
'forbidden',
|
|
72
|
+
'invalid_request',
|
|
73
|
+
'server_error',
|
|
74
|
+
];
|
|
75
|
+
/**
|
|
76
|
+
* Closed enum for `POST /author-keys` register responses. An operator
|
|
77
|
+
* registers a per-scope Ed25519 public key with the registry so
|
|
78
|
+
* future `POST /publish` calls signed by the matching private key
|
|
79
|
+
* validate against an `AuthorKeyRow`.
|
|
80
|
+
*
|
|
81
|
+
* - `unauthorized` — missing or invalid caller credentials.
|
|
82
|
+
* - `invalid_request` — body missing `publicKeyBase64`, malformed
|
|
83
|
+
* base64, or wrong byte length.
|
|
84
|
+
* - `key_conflict` — a row already exists for `(subject, keyId)`
|
|
85
|
+
* with a different `publicKeyBase64`. Same
|
|
86
|
+
* publicKey is treated as idempotent → 200.
|
|
87
|
+
* - `server_error` — unexpected adapter failure.
|
|
88
|
+
*/
|
|
89
|
+
export const REGISTER_AUTHOR_KEY_ERROR_CODES = [
|
|
90
|
+
'unauthorized',
|
|
91
|
+
'invalid_request',
|
|
92
|
+
'key_conflict',
|
|
93
|
+
'server_error',
|
|
94
|
+
];
|
|
95
|
+
/**
|
|
96
|
+
* Closed enum for `GET /pkg/{scope}/{name}` list-versions responses.
|
|
97
|
+
*
|
|
98
|
+
* - `invalid_request` — missing or malformed `artifactId`.
|
|
99
|
+
* - `not_found` — no metadata row for `artifactId`. Distinct
|
|
100
|
+
* from "metadata present but every version is
|
|
101
|
+
* private + caller unauthed" (that path returns
|
|
102
|
+
* 200 with `versions: []` — exposing 404 vs
|
|
103
|
+
* empty would leak private-row existence).
|
|
104
|
+
* - `server_error` — unexpected adapter failure.
|
|
105
|
+
*/
|
|
106
|
+
export const LIST_VERSIONS_ERROR_CODES = [
|
|
107
|
+
'invalid_request',
|
|
108
|
+
'not_found',
|
|
109
|
+
'server_error',
|
|
110
|
+
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode a base64 string into bytes. Returns `undefined` on malformed
|
|
3
|
+
* input so the caller can surface a domain-specific error rather than
|
|
4
|
+
* a thrown exception.
|
|
5
|
+
*
|
|
6
|
+
* `Buffer.from(b64, 'base64')` is permissive — it ignores invalid
|
|
7
|
+
* chars rather than throwing. To detect malformed input, re-encode and
|
|
8
|
+
* compare against a whitespace-stripped original.
|
|
9
|
+
*/
|
|
10
|
+
export declare function safeBase64Decode(b64: string): Uint8Array | undefined;
|
|
11
|
+
/** Base64-encode bytes. */
|
|
12
|
+
export declare function base64Encode(bytes: Uint8Array): string;
|
|
13
|
+
/** SHA-384 of bytes, base64-encoded. The wire form for `bundleSha384`. */
|
|
14
|
+
export declare function sha384Base64(bytes: Uint8Array): string;
|
|
15
|
+
//# sourceMappingURL=base64.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/utils/base64.ts"],"names":[],"mappings":"AAUA;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAQpE;AAED,2BAA2B;AAC3B,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 + SHA helpers used by the publish op. Pulled out so the op
|
|
3
|
+
* file stays focused on policy + flow control.
|
|
4
|
+
*
|
|
5
|
+
* Uses `node:crypto` for SHA-384. The wider browser-portable goal of
|
|
6
|
+
* registry-core means we MAY swap to `@noble/hashes` later — the
|
|
7
|
+
* interface is `Uint8Array → string` so the swap is structural.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
/**
|
|
11
|
+
* Decode a base64 string into bytes. Returns `undefined` on malformed
|
|
12
|
+
* input so the caller can surface a domain-specific error rather than
|
|
13
|
+
* a thrown exception.
|
|
14
|
+
*
|
|
15
|
+
* `Buffer.from(b64, 'base64')` is permissive — it ignores invalid
|
|
16
|
+
* chars rather than throwing. To detect malformed input, re-encode and
|
|
17
|
+
* compare against a whitespace-stripped original.
|
|
18
|
+
*/
|
|
19
|
+
export function safeBase64Decode(b64) {
|
|
20
|
+
const buf = Buffer.from(b64, 'base64');
|
|
21
|
+
const reencoded = buf.toString('base64');
|
|
22
|
+
const normalize = (s) => s.replace(/=+$/, '').replace(/\s/g, '');
|
|
23
|
+
if (normalize(reencoded) !== normalize(b64)) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
27
|
+
}
|
|
28
|
+
/** Base64-encode bytes. */
|
|
29
|
+
export function base64Encode(bytes) {
|
|
30
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64');
|
|
31
|
+
}
|
|
32
|
+
/** SHA-384 of bytes, base64-encoded. The wire form for `bundleSha384`. */
|
|
33
|
+
export function sha384Base64(bytes) {
|
|
34
|
+
return createHash('sha384').update(bytes).digest('base64');
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local semver comparison — supports `MAJOR.MINOR.PATCH` + optional
|
|
3
|
+
* `-pre.release` + (ignored) `+build.metadata`. Implemented locally to
|
|
4
|
+
* avoid a `semver` runtime dep for the very narrow comparison
|
|
5
|
+
* registry-core needs (decide whether a newly-published version is
|
|
6
|
+
* the latest).
|
|
7
|
+
*
|
|
8
|
+
* Returns `-1` / `0` / `1` matching `Array.prototype.sort`. Pre-release
|
|
9
|
+
* versions sort lower than the corresponding non-pre version
|
|
10
|
+
* (`1.0.0-alpha < 1.0.0`) per semver.org. Build metadata is ignored.
|
|
11
|
+
*/
|
|
12
|
+
export declare function compareSemver(a: string, b: string): -1 | 0 | 1;
|
|
13
|
+
//# sourceMappingURL=semver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../../src/utils/semver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAgD9D"}
|