@nitida/sdk 0.27.0 → 0.28.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.
- package/AGENTS.md +32 -7
- package/README.md +30 -3
- package/dist/index.d.ts +42 -8
- package/dist/index.js +21 -5
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +21 -5
- package/dist/server.js.map +1 -1
- package/dist/web.d.ts +1 -1
- package/dist/web.js +21 -5
- package/dist/web.js.map +1 -1
- package/package.json +2 -2
- package/skills/nitida-sdk/SKILL.md +32 -7
- package/src/index.ts +54 -9
- package/src/server/index.ts +4 -0
- package/src/web/index.ts +4 -0
package/src/index.ts
CHANGED
|
@@ -48,6 +48,8 @@ import {
|
|
|
48
48
|
getVideoTransformUrl,
|
|
49
49
|
hasPreset,
|
|
50
50
|
invalidateSlotCache,
|
|
51
|
+
isRequestablePreset,
|
|
52
|
+
REQUESTABLE_PRESETS,
|
|
51
53
|
type RequestablePreset,
|
|
52
54
|
type ResolveSlotOptions,
|
|
53
55
|
resolveSlot,
|
|
@@ -58,6 +60,7 @@ import {
|
|
|
58
60
|
setCdnBase,
|
|
59
61
|
setTenantId,
|
|
60
62
|
type TransformOptions,
|
|
63
|
+
toRequestablePresets,
|
|
61
64
|
type VariantEntryPreset,
|
|
62
65
|
type VariantPreset,
|
|
63
66
|
} from "@nitida/asset-client";
|
|
@@ -114,12 +117,25 @@ export type NitidaClientOptions = {
|
|
|
114
117
|
* Tenant's HMAC signing key for transform URLs (Phase 3). Required
|
|
115
118
|
* only when calling `aq.transform(asset, opts, { sign: true })`.
|
|
116
119
|
*
|
|
117
|
-
* 32 random bytes, generated server-side on tenant creation
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
120
|
+
* 32 random bytes, generated server-side on tenant creation.
|
|
121
|
+
*
|
|
122
|
+
* **Where you get it: the response to your project's creation, once.**
|
|
123
|
+
* `POST /admin/projects` returns `signingKey` next to the three API keys,
|
|
124
|
+
* and the console shows it in the same panel. It is shown there and nowhere
|
|
125
|
+
* else — save it with the keys.
|
|
126
|
+
*
|
|
127
|
+
* **Never saw one?** Projects created before 2026-08-23 were not handed it,
|
|
128
|
+
* and no endpoint shows you the current one. If you have not signed any URLs
|
|
129
|
+
* yet — true of every project that has not shipped private assets — ask for
|
|
130
|
+
* a rotation: with nothing in flight it invalidates nothing and is free. If
|
|
131
|
+
* you already have signed URLs circulating, ask for the current key instead.
|
|
132
|
+
*
|
|
133
|
+
* Either way it is one request to the platform operator:
|
|
134
|
+
* `POST /admin/projects/:code/rotate-signing-key` needs a SYSTEM-scope
|
|
135
|
+
* credential, and your own admin key answers `403 SYSTEM_KEY_REQUIRED`.
|
|
136
|
+
*
|
|
137
|
+
* **Keep it server-side only** — do not ship in `NEXT_PUBLIC_*` env vars.
|
|
138
|
+
* Sign URLs from a BFF route handler, or pre-sign at build time.
|
|
123
139
|
*/
|
|
124
140
|
signingKey?: string;
|
|
125
141
|
};
|
|
@@ -227,6 +243,7 @@ export type {
|
|
|
227
243
|
export {
|
|
228
244
|
accessMessage,
|
|
229
245
|
assertPublic,
|
|
246
|
+
assertSha,
|
|
230
247
|
bestTextContrast,
|
|
231
248
|
computeVariantDimensions,
|
|
232
249
|
configureSlotResolver,
|
|
@@ -253,12 +270,14 @@ export {
|
|
|
253
270
|
hasPreset,
|
|
254
271
|
hlsLadderAlignment,
|
|
255
272
|
invalidateSlotCache,
|
|
273
|
+
isRequestablePreset,
|
|
256
274
|
iteratePaletteSwatches,
|
|
257
275
|
PRESET_EXT,
|
|
258
276
|
PRESET_LONG,
|
|
259
277
|
PRESET_MAX_DIM,
|
|
260
278
|
PRESET_SHORT,
|
|
261
279
|
pickAmbientBackground,
|
|
280
|
+
REQUESTABLE_PRESETS,
|
|
262
281
|
relativeLuminance,
|
|
263
282
|
resolveSlot,
|
|
264
283
|
resolveSlots,
|
|
@@ -268,6 +287,7 @@ export {
|
|
|
268
287
|
signAccessUrl,
|
|
269
288
|
signTransformUrl,
|
|
270
289
|
TRANSFORM_WIDTHS,
|
|
290
|
+
toRequestablePresets,
|
|
271
291
|
} from "@nitida/asset-client";
|
|
272
292
|
|
|
273
293
|
// ---------------------------------------------------------------------------
|
|
@@ -530,7 +550,12 @@ export type ComposeMarketingResult = {
|
|
|
530
550
|
class AssetsApi {
|
|
531
551
|
constructor(private readonly opts: NitidaClientOptions) {}
|
|
532
552
|
|
|
533
|
-
/**
|
|
553
|
+
/**
|
|
554
|
+
* Look up an asset by sha256. Accepts the full 64-hex digest that
|
|
555
|
+
* `upload()` returns as `sha256`, or the 16-char short prefix that appears
|
|
556
|
+
* in every CDN URL. Returns null on 404; throws with a message naming the
|
|
557
|
+
* expected shape if the string is neither form.
|
|
558
|
+
*/
|
|
534
559
|
async byHash(sha256: string): Promise<AssetDTO | null> {
|
|
535
560
|
const r = await fetch(
|
|
536
561
|
endpointHref(this.opts, `/assets/by-hash/${sha256}`),
|
|
@@ -1018,6 +1043,22 @@ const DEFAULT_UPLOAD_PRESETS: RequestablePreset[] = ["original"];
|
|
|
1018
1043
|
export type UploadResult = {
|
|
1019
1044
|
assetId: string;
|
|
1020
1045
|
sha256: string;
|
|
1046
|
+
/**
|
|
1047
|
+
* The SAME 16-hex prefix an `AssetDTO` carries, so the result of an upload can
|
|
1048
|
+
* be handed straight to any URL builder.
|
|
1049
|
+
*
|
|
1050
|
+
* ⭐ It exists because it did not, and that cost a real 404. A Haiku agent
|
|
1051
|
+
* evaluating the SDK on 2026-08-23 did the most natural thing there is —
|
|
1052
|
+
* `transform(await upload(file), { width: 1280 })` — and got
|
|
1053
|
+
* `https://8ok.uk/t/width=1280/undefined.webp`. The builders read `sha`; this
|
|
1054
|
+
* type only had `sha256`. TypeScript caught it; running through `bun`, or in
|
|
1055
|
+
* plain JS, nothing did.
|
|
1056
|
+
*
|
|
1057
|
+
* The guard (`assertSha`) is the backstop. This field is the actual fix: the
|
|
1058
|
+
* obvious call is now the correct one, which is worth more than a good error
|
|
1059
|
+
* message about the wrong one.
|
|
1060
|
+
*/
|
|
1061
|
+
sha: string;
|
|
1021
1062
|
cdnUrl: string;
|
|
1022
1063
|
};
|
|
1023
1064
|
|
|
@@ -1279,7 +1320,7 @@ export class NitidaClient {
|
|
|
1279
1320
|
if (!this.opts.signingKey) {
|
|
1280
1321
|
throw new Error(
|
|
1281
1322
|
"aq.transform({ sign: true }) requires `signingKey` in NitidaClientOptions. " +
|
|
1282
|
-
"No signingKey on this client.
|
|
1323
|
+
"No signingKey on this client. It is returned ONCE, in the response that creates your project (POST /admin/projects → `signingKey`, next to the three API keys; the console shows it in the same panel). If you never saw one — projects created before 2026-08-23 were not handed it — ask the platform operator to rotate: with no signed URLs in flight that invalidates nothing and is free. If you DO have signed URLs circulating, ask for the current key instead, because rotating would kill them. Then pass it to the SDK constructor on a SERVER-side instance only.",
|
|
1283
1324
|
);
|
|
1284
1325
|
}
|
|
1285
1326
|
// Signed path — custom (off-ladder) widths allowed. Empty opts → no
|
|
@@ -1317,7 +1358,8 @@ export class NitidaClient {
|
|
|
1317
1358
|
if (!signOpts?.sign) return getTransformSrcSet(asset, widths, extraOpts);
|
|
1318
1359
|
if (!this.opts.signingKey) {
|
|
1319
1360
|
throw new Error(
|
|
1320
|
-
"aq.transformSrcSet({ sign: true }) requires `signingKey` in NitidaClientOptions."
|
|
1361
|
+
"aq.transformSrcSet({ sign: true }) requires `signingKey` in NitidaClientOptions. " +
|
|
1362
|
+
"It was returned ONCE, by the response that created your project (POST /admin/projects → `signingKey`). See the `signingKey` docs on NitidaClientOptions.",
|
|
1321
1363
|
);
|
|
1322
1364
|
}
|
|
1323
1365
|
const key = this.opts.signingKey;
|
|
@@ -1563,6 +1605,7 @@ export class NitidaClient {
|
|
|
1563
1605
|
return {
|
|
1564
1606
|
assetId: existing.id,
|
|
1565
1607
|
sha256: sha,
|
|
1608
|
+
sha: sha.slice(0, 16),
|
|
1566
1609
|
cdnUrl: this.urlFor(existing, this.bestPresetForAsset(existing, mime)),
|
|
1567
1610
|
};
|
|
1568
1611
|
}
|
|
@@ -1588,6 +1631,7 @@ export class NitidaClient {
|
|
|
1588
1631
|
return {
|
|
1589
1632
|
assetId: presign.asset.id,
|
|
1590
1633
|
sha256: sha,
|
|
1634
|
+
sha: sha.slice(0, 16),
|
|
1591
1635
|
cdnUrl: this.urlFor(presign.asset, this.defaultPresetForMime(mime)),
|
|
1592
1636
|
};
|
|
1593
1637
|
}
|
|
@@ -1638,6 +1682,7 @@ export class NitidaClient {
|
|
|
1638
1682
|
return {
|
|
1639
1683
|
assetId,
|
|
1640
1684
|
sha256: sha,
|
|
1685
|
+
sha: sha.slice(0, 16),
|
|
1641
1686
|
cdnUrl: this.urlFor(final, this.bestPresetForAsset(final, mime)),
|
|
1642
1687
|
};
|
|
1643
1688
|
}
|
package/src/server/index.ts
CHANGED
|
@@ -96,6 +96,7 @@ export {
|
|
|
96
96
|
type AssetVariant,
|
|
97
97
|
accessMessage,
|
|
98
98
|
assertPublic,
|
|
99
|
+
assertSha,
|
|
99
100
|
bestTextContrast,
|
|
100
101
|
type ComposeMarketingComposition,
|
|
101
102
|
type ComposeMarketingOptions,
|
|
@@ -128,6 +129,7 @@ export {
|
|
|
128
129
|
hasPreset,
|
|
129
130
|
hlsLadderAlignment,
|
|
130
131
|
invalidateSlotCache,
|
|
132
|
+
isRequestablePreset,
|
|
131
133
|
isUniversallyPlayableAudio,
|
|
132
134
|
iteratePaletteSwatches,
|
|
133
135
|
mimeFromFileName,
|
|
@@ -139,6 +141,7 @@ export {
|
|
|
139
141
|
PRESET_SHORT,
|
|
140
142
|
type PresignUploadUrlOptions,
|
|
141
143
|
pickAmbientBackground,
|
|
144
|
+
REQUESTABLE_PRESETS,
|
|
142
145
|
type RegenerateResult,
|
|
143
146
|
type RequestablePreset,
|
|
144
147
|
type ResolveSlotOptions,
|
|
@@ -162,6 +165,7 @@ export {
|
|
|
162
165
|
type TransformGravity,
|
|
163
166
|
type TransformOptions,
|
|
164
167
|
type TransformWidth,
|
|
168
|
+
toRequestablePresets,
|
|
165
169
|
type UploadOptions,
|
|
166
170
|
type UploadResult,
|
|
167
171
|
type UploadUrlResult,
|
package/src/web/index.ts
CHANGED
|
@@ -113,6 +113,7 @@ export {
|
|
|
113
113
|
type AssetVariant,
|
|
114
114
|
accessMessage,
|
|
115
115
|
assertPublic,
|
|
116
|
+
assertSha,
|
|
116
117
|
bestTextContrast,
|
|
117
118
|
type ComposeMarketingComposition,
|
|
118
119
|
type ComposeMarketingOptions,
|
|
@@ -145,6 +146,7 @@ export {
|
|
|
145
146
|
hasPreset,
|
|
146
147
|
hlsLadderAlignment,
|
|
147
148
|
invalidateSlotCache,
|
|
149
|
+
isRequestablePreset,
|
|
148
150
|
isUniversallyPlayableAudio,
|
|
149
151
|
iteratePaletteSwatches,
|
|
150
152
|
mimeFromFileName,
|
|
@@ -155,6 +157,7 @@ export {
|
|
|
155
157
|
PRESET_SHORT,
|
|
156
158
|
type PresignUploadUrlOptions,
|
|
157
159
|
pickAmbientBackground,
|
|
160
|
+
REQUESTABLE_PRESETS,
|
|
158
161
|
type RegenerateResult,
|
|
159
162
|
type RequestablePreset,
|
|
160
163
|
type ResolveSlotOptions,
|
|
@@ -178,6 +181,7 @@ export {
|
|
|
178
181
|
type TransformGravity,
|
|
179
182
|
type TransformOptions,
|
|
180
183
|
type TransformWidth,
|
|
184
|
+
toRequestablePresets,
|
|
181
185
|
type UploadOptions,
|
|
182
186
|
type UploadResult,
|
|
183
187
|
type UploadUrlResult,
|