@nitida/sdk 0.27.1 → 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 +16 -0
- package/README.md +30 -3
- package/dist/index.d.ts +26 -8
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +16 -5
- package/dist/server.js.map +1 -1
- package/dist/web.d.ts +1 -1
- package/dist/web.js +16 -5
- package/dist/web.js.map +1 -1
- package/package.json +2 -2
- package/skills/nitida-sdk/SKILL.md +16 -0
- package/src/index.ts +34 -9
- package/src/server/index.ts +3 -0
- package/src/web/index.ts +3 -0
package/AGENTS.md
CHANGED
|
@@ -101,6 +101,22 @@ await getPrivateTransformUrl(asset, { width: 1280 }, signingKey, { expiresInSeco
|
|
|
101
101
|
- **`exp` is mandatory**; revocation is *"within a minute"* (60 s TTL at the edge).
|
|
102
102
|
- **The signing key is a backend secret** — it mints URLs for every private
|
|
103
103
|
asset the tenant owns.
|
|
104
|
+
- **⭐ Where the signing key comes from: the response that CREATED your
|
|
105
|
+
project, once.** `POST /admin/projects` returns `signingKey` next to the
|
|
106
|
+
three API keys, and the console shows it in the same panel. Nothing else
|
|
107
|
+
hands it out — `GET /admin/projects/:code` does **not** include it. If it is
|
|
108
|
+
lost, the only endpoint that returns a key is
|
|
109
|
+
`POST /admin/projects/:code/rotate-signing-key`, which **invalidates every
|
|
110
|
+
URL already signed** and needs the system-scope key the platform operator
|
|
111
|
+
holds. A tenant with nothing signed yet can rotate for free; a live one
|
|
112
|
+
cannot, which is why you save it at creation.
|
|
113
|
+
- **⭐ Already have a project and never saw a signing key?** Then you never got
|
|
114
|
+
one — projects created before 2026-08-23 were not handed it, and no endpoint
|
|
115
|
+
shows you the current one. **If you have not signed any URLs yet, ask us to
|
|
116
|
+
rotate: with nothing in flight, rotation invalidates nothing and is free.**
|
|
117
|
+
If you already have signed URLs circulating, ask us for the current key
|
|
118
|
+
instead. This is the wall the T5 agent hit, and the sentence that was
|
|
119
|
+
missing.
|
|
104
120
|
|
|
105
121
|
## Two ways an image gets smaller, and only one of them is yours to call
|
|
106
122
|
|
package/README.md
CHANGED
|
@@ -259,8 +259,11 @@ const heroes = await aq.slots.resolveMany([
|
|
|
259
259
|
"storefront.home.tile-2",
|
|
260
260
|
]);
|
|
261
261
|
|
|
262
|
-
// Lower-level operations.
|
|
262
|
+
// Lower-level operations. `byHash` takes the full 64-hex sha256 that
|
|
263
|
+
// `upload()` returns as `.sha256`, OR its 16-char prefix — the short form
|
|
264
|
+
// that appears inside every CDN URL. Both resolve to the same asset.
|
|
263
265
|
const asset = await aq.assets.byHash("3c…<64 hex>…");
|
|
266
|
+
const same = await aq.assets.byHash("3c8f1a20b7d94e05"); // 16-char prefix ✓
|
|
264
267
|
const { assets, nextCursor } = await aq.assets.list({ limit: 50 });
|
|
265
268
|
|
|
266
269
|
// Uploads — hash-deduped; returns the canonical v2 URL immediately.
|
|
@@ -894,6 +897,29 @@ as they specify the same params.
|
|
|
894
897
|
|
|
895
898
|
Every tenant has an HMAC-SHA256 signing key — 32 random bytes, generated
|
|
896
899
|
on tenant creation.
|
|
900
|
+
|
|
901
|
+
> **Where you get it: the response that created your project, once.**
|
|
902
|
+
> `POST /admin/projects` returns `signingKey` next to the three API keys, and
|
|
903
|
+
> the console shows it in the same panel. Save it with the keys — nothing else
|
|
904
|
+
> hands it out. In particular `GET /admin/projects/:code` does **not** return
|
|
905
|
+
> it, and neither does any tenant-scoped endpoint.
|
|
906
|
+
>
|
|
907
|
+
> **Your project already exists and you never saw a signing key?** Then you
|
|
908
|
+
> never got one: projects created before 2026-08-23 were not handed it, and
|
|
909
|
+
> there is no endpoint that shows you the current one. This is the exact wall
|
|
910
|
+
> to hit, so here is the way through it:
|
|
911
|
+
>
|
|
912
|
+
> - **If you have not signed any URLs yet** — which is true of every project
|
|
913
|
+
> that has not shipped private assets — ask us to rotate. Rotation returns a
|
|
914
|
+
> key, and with nothing in flight it invalidates nothing. It is free.
|
|
915
|
+
> - **If you already have signed URLs in circulation**, rotation kills them.
|
|
916
|
+
> Ask us for the current key instead; we can read it.
|
|
917
|
+
>
|
|
918
|
+
> Either way it is one request to us, because
|
|
919
|
+
> `POST /admin/projects/:code/rotate-signing-key` needs the system-scope key
|
|
920
|
+
> the platform operator holds — your own admin key answers
|
|
921
|
+
> `403 SYSTEM_KEY_REQUIRED`.
|
|
922
|
+
|
|
897
923
|
Optionally enable `strict_transforms = true` to reject unsigned URLs
|
|
898
924
|
with a 401 — useful when transform URLs leak from a private surface
|
|
899
925
|
(internal admin, b2b portal) and you don't want third parties
|
|
@@ -905,7 +931,8 @@ const aq = new NitidaClient({
|
|
|
905
931
|
apiKey: process.env.AQUIENPZ_API_KEY!,
|
|
906
932
|
tenantCode: "your-tenant",
|
|
907
933
|
tenantId: 42,
|
|
908
|
-
//
|
|
934
|
+
// Handed to you once, by the response that created the project.
|
|
935
|
+
// do NOT ship to the browser.
|
|
909
936
|
signingKey: process.env.AQUIENPZ_SIGNING_KEY!,
|
|
910
937
|
});
|
|
911
938
|
|
|
@@ -1304,7 +1331,7 @@ API key tiers:
|
|
|
1304
1331
|
| `aq.slots` | `bind(key, {assetId, preset})` | Admin rebind |
|
|
1305
1332
|
| `aq.slots` | `unbind(key)` | Remove binding |
|
|
1306
1333
|
| `aq.slots` | `invalidateCache(key?)` | After admin rebind |
|
|
1307
|
-
| `aq.assets` | `byHash(sha)` / `byHashes([])` | Lookup |
|
|
1334
|
+
| `aq.assets` | `byHash(sha)` / `byHashes([])` | Lookup — full 64-hex sha **or** its 16-char prefix |
|
|
1308
1335
|
| `aq.assets` | `list({limit, cursor})` | Paginated |
|
|
1309
1336
|
| `aq.assets` | `get(id)` | Full DTO |
|
|
1310
1337
|
| `aq.assets` | `patchMetadata(id, {…})` | Merge JSON |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ResolveSlotOptions, SlotResolution, SlotDTO, VariantPreset, AssetDTO, AssetVariant, RequestablePreset, TransformOptions, SignedTransformOptions } from '@nitida/asset-client';
|
|
2
|
-
export { AssetDTO, AssetPalette, AssetVariant, HlsRung, PRESET_EXT, PRESET_LONG, PRESET_MAX_DIM, PRESET_SHORT, PaletteSwatch, RequestablePreset, ResolveSlotOptions, SignAccessOptions, SignedTransformOptions, SlotDTO, SlotResolution, TRANSFORM_WIDTHS, TransformEffect, TransformFit, TransformFormat, TransformGravity, TransformOptions, TransformWidth, VariantEntryPreset, VariantPreset, VisibilityHint, accessMessage, assertPublic, assertSha, bestTextContrast, computeVariantDimensions, configureSlotResolver, contrastRatio, deriveAccessKey, extractAssetSha, getAmbientGradient, getAssetDimensions, getAssetSrcSet, getAssetUrl, getCdnBase, getHlsLadder, getHlsStreamingUrl, getPaletteBlurBackground, getPaletteCssVars, getPrivateAssetUrl, getPrivateTransformUrl, getSignedTransformUrl, getTenantId, getTextColorForBackground, getTransformSrcSet, getTransformUrl, getVideoTransformUrl, hasPreset, hlsLadderAlignment, invalidateSlotCache, iteratePaletteSwatches, pickAmbientBackground, relativeLuminance, resolveSlot, resolveSlots, serializeTransform, setCdnBase, setTenantId, signAccessUrl, signTransformUrl } from '@nitida/asset-client';
|
|
2
|
+
export { AssetDTO, AssetPalette, AssetVariant, HlsRung, PRESET_EXT, PRESET_LONG, PRESET_MAX_DIM, PRESET_SHORT, PaletteSwatch, REQUESTABLE_PRESETS, RequestablePreset, ResolveSlotOptions, SignAccessOptions, SignedTransformOptions, SlotDTO, SlotResolution, TRANSFORM_WIDTHS, TransformEffect, TransformFit, TransformFormat, TransformGravity, TransformOptions, TransformWidth, VariantEntryPreset, VariantPreset, VisibilityHint, accessMessage, assertPublic, assertSha, bestTextContrast, computeVariantDimensions, configureSlotResolver, contrastRatio, deriveAccessKey, extractAssetSha, getAmbientGradient, getAssetDimensions, getAssetSrcSet, getAssetUrl, getCdnBase, getHlsLadder, getHlsStreamingUrl, getPaletteBlurBackground, getPaletteCssVars, getPrivateAssetUrl, getPrivateTransformUrl, getSignedTransformUrl, getTenantId, getTextColorForBackground, getTransformSrcSet, getTransformUrl, getVideoTransformUrl, hasPreset, hlsLadderAlignment, invalidateSlotCache, isRequestablePreset, iteratePaletteSwatches, pickAmbientBackground, relativeLuminance, resolveSlot, resolveSlots, serializeTransform, setCdnBase, setTenantId, signAccessUrl, signTransformUrl, toRequestablePresets } from '@nitida/asset-client';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Which audio uploads already play everywhere — the single source of truth for
|
|
@@ -119,12 +119,25 @@ type NitidaClientOptions = {
|
|
|
119
119
|
* Tenant's HMAC signing key for transform URLs (Phase 3). Required
|
|
120
120
|
* only when calling `aq.transform(asset, opts, { sign: true })`.
|
|
121
121
|
*
|
|
122
|
-
* 32 random bytes, generated server-side on tenant creation
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
122
|
+
* 32 random bytes, generated server-side on tenant creation.
|
|
123
|
+
*
|
|
124
|
+
* **Where you get it: the response to your project's creation, once.**
|
|
125
|
+
* `POST /admin/projects` returns `signingKey` next to the three API keys,
|
|
126
|
+
* and the console shows it in the same panel. It is shown there and nowhere
|
|
127
|
+
* else — save it with the keys.
|
|
128
|
+
*
|
|
129
|
+
* **Never saw one?** Projects created before 2026-08-23 were not handed it,
|
|
130
|
+
* and no endpoint shows you the current one. If you have not signed any URLs
|
|
131
|
+
* yet — true of every project that has not shipped private assets — ask for
|
|
132
|
+
* a rotation: with nothing in flight it invalidates nothing and is free. If
|
|
133
|
+
* you already have signed URLs circulating, ask for the current key instead.
|
|
134
|
+
*
|
|
135
|
+
* Either way it is one request to the platform operator:
|
|
136
|
+
* `POST /admin/projects/:code/rotate-signing-key` needs a SYSTEM-scope
|
|
137
|
+
* credential, and your own admin key answers `403 SYSTEM_KEY_REQUIRED`.
|
|
138
|
+
*
|
|
139
|
+
* **Keep it server-side only** — do not ship in `NEXT_PUBLIC_*` env vars.
|
|
140
|
+
* Sign URLs from a BFF route handler, or pre-sign at build time.
|
|
128
141
|
*/
|
|
129
142
|
signingKey?: string;
|
|
130
143
|
};
|
|
@@ -319,7 +332,12 @@ type ComposeMarketingResult = {
|
|
|
319
332
|
declare class AssetsApi {
|
|
320
333
|
private readonly opts;
|
|
321
334
|
constructor(opts: NitidaClientOptions);
|
|
322
|
-
/**
|
|
335
|
+
/**
|
|
336
|
+
* Look up an asset by sha256. Accepts the full 64-hex digest that
|
|
337
|
+
* `upload()` returns as `sha256`, or the 16-char short prefix that appears
|
|
338
|
+
* in every CDN URL. Returns null on 404; throws with a message naming the
|
|
339
|
+
* expected shape if the string is neither form.
|
|
340
|
+
*/
|
|
323
341
|
byHash(sha256: string): Promise<AssetDTO | null>;
|
|
324
342
|
/** Bulk lookup by sha256s. */
|
|
325
343
|
byHashes(hashes: string[]): Promise<{
|
package/dist/index.js
CHANGED
|
@@ -53,12 +53,14 @@ import {
|
|
|
53
53
|
hasPreset as hasPreset2,
|
|
54
54
|
hlsLadderAlignment,
|
|
55
55
|
invalidateSlotCache as invalidateSlotCache2,
|
|
56
|
+
isRequestablePreset as isRequestablePreset2,
|
|
56
57
|
iteratePaletteSwatches,
|
|
57
58
|
PRESET_EXT,
|
|
58
59
|
PRESET_LONG,
|
|
59
60
|
PRESET_MAX_DIM,
|
|
60
61
|
PRESET_SHORT,
|
|
61
62
|
pickAmbientBackground,
|
|
63
|
+
REQUESTABLE_PRESETS as REQUESTABLE_PRESETS2,
|
|
62
64
|
relativeLuminance,
|
|
63
65
|
resolveSlot as resolveSlot2,
|
|
64
66
|
resolveSlots as resolveSlots2,
|
|
@@ -67,7 +69,8 @@ import {
|
|
|
67
69
|
setTenantId as setTenantId2,
|
|
68
70
|
signAccessUrl,
|
|
69
71
|
signTransformUrl,
|
|
70
|
-
TRANSFORM_WIDTHS
|
|
72
|
+
TRANSFORM_WIDTHS,
|
|
73
|
+
toRequestablePresets as toRequestablePresets2
|
|
71
74
|
} from "@nitida/asset-client";
|
|
72
75
|
function endpointUrl(opts, path, searchParams) {
|
|
73
76
|
const endpoint = opts.endpoint.replace(/\/+$/, "");
|
|
@@ -199,7 +202,12 @@ var AssetsApi = class {
|
|
|
199
202
|
this.opts = opts;
|
|
200
203
|
}
|
|
201
204
|
opts;
|
|
202
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Look up an asset by sha256. Accepts the full 64-hex digest that
|
|
207
|
+
* `upload()` returns as `sha256`, or the 16-char short prefix that appears
|
|
208
|
+
* in every CDN URL. Returns null on 404; throws with a message naming the
|
|
209
|
+
* expected shape if the string is neither form.
|
|
210
|
+
*/
|
|
203
211
|
async byHash(sha256) {
|
|
204
212
|
const r = await fetch(
|
|
205
213
|
endpointHref(this.opts, `/assets/by-hash/${sha256}`),
|
|
@@ -572,7 +580,7 @@ var NitidaClient = class {
|
|
|
572
580
|
}
|
|
573
581
|
if (!this.opts.signingKey) {
|
|
574
582
|
throw new Error(
|
|
575
|
-
"aq.transform({ sign: true }) requires `signingKey` in NitidaClientOptions. No signingKey on this client.
|
|
583
|
+
"aq.transform({ sign: true }) requires `signingKey` in NitidaClientOptions. No signingKey on this client. It is returned ONCE, in the response that creates your project (POST /admin/projects \u2192 `signingKey`, next to the three API keys; the console shows it in the same panel). If you never saw one \u2014 projects created before 2026-08-23 were not handed it \u2014 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."
|
|
576
584
|
);
|
|
577
585
|
}
|
|
578
586
|
return getSignedTransformUrl(asset, opts, this.opts.signingKey) ?? Promise.resolve(this.urlFor(asset, "lg"));
|
|
@@ -581,7 +589,7 @@ var NitidaClient = class {
|
|
|
581
589
|
if (!signOpts?.sign) return getTransformSrcSet(asset, widths, extraOpts);
|
|
582
590
|
if (!this.opts.signingKey) {
|
|
583
591
|
throw new Error(
|
|
584
|
-
"aq.transformSrcSet({ sign: true }) requires `signingKey` in NitidaClientOptions."
|
|
592
|
+
"aq.transformSrcSet({ sign: true }) requires `signingKey` in NitidaClientOptions. It was returned ONCE, by the response that created your project (POST /admin/projects \u2192 `signingKey`). See the `signingKey` docs on NitidaClientOptions."
|
|
585
593
|
);
|
|
586
594
|
}
|
|
587
595
|
const key = this.opts.signingKey;
|
|
@@ -860,6 +868,7 @@ export {
|
|
|
860
868
|
PRESET_LONG,
|
|
861
869
|
PRESET_MAX_DIM,
|
|
862
870
|
PRESET_SHORT,
|
|
871
|
+
REQUESTABLE_PRESETS2 as REQUESTABLE_PRESETS,
|
|
863
872
|
TRANSFORM_WIDTHS,
|
|
864
873
|
accessMessage,
|
|
865
874
|
assertPublic,
|
|
@@ -890,6 +899,7 @@ export {
|
|
|
890
899
|
hasPreset2 as hasPreset,
|
|
891
900
|
hlsLadderAlignment,
|
|
892
901
|
invalidateSlotCache2 as invalidateSlotCache,
|
|
902
|
+
isRequestablePreset2 as isRequestablePreset,
|
|
893
903
|
isUniversallyPlayableAudio,
|
|
894
904
|
iteratePaletteSwatches,
|
|
895
905
|
mimeFromFileName,
|
|
@@ -901,6 +911,7 @@ export {
|
|
|
901
911
|
setCdnBase2 as setCdnBase,
|
|
902
912
|
setTenantId2 as setTenantId,
|
|
903
913
|
signAccessUrl,
|
|
904
|
-
signTransformUrl
|
|
914
|
+
signTransformUrl,
|
|
915
|
+
toRequestablePresets2 as toRequestablePresets
|
|
905
916
|
};
|
|
906
917
|
//# sourceMappingURL=index.js.map
|