@gradial/aci 0.1.52-rc.40 → 0.1.52-rc.42
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Prerelease versions are no longer committed. Canary builds
|
|
8
|
+
(`@gradial/aci@canary`) publish automatically from every SDK change on
|
|
9
|
+
`main`; release candidates (`@gradial/aci@rc`) and stable releases publish
|
|
10
|
+
on demand. All are prereleases or releases of the next stable version.
|
|
11
|
+
|
|
12
|
+
## 0.1.52-rc.41
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Shared edge claims support collection-free external-audience delivery.
|
|
17
|
+
Personalization requires a recognized issuer marker; signed older cookies
|
|
18
|
+
remain valid evidence for consent withdrawal.
|
|
19
|
+
|
|
3
20
|
## 0.1.52-rc.40
|
|
4
21
|
|
|
5
22
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agentic Content Infrastructure SDK
|
|
2
2
|
|
|
3
|
-
`@gradial/aci` `0.1.52-rc.
|
|
3
|
+
`@gradial/aci` `0.1.52-rc.42` is a pre-1.0 public-surface reset for the ACI
|
|
4
4
|
client SDK. Breaking changes from the old `0.1.x` accidental surface are
|
|
5
5
|
intentional: the root import is framework-neutral, framework runtime behavior is
|
|
6
6
|
behind explicit subpaths, and the first required customer path is React/Next.
|
|
@@ -8,7 +8,7 @@ behind explicit subpaths, and the first required customer path is React/Next.
|
|
|
8
8
|
## Install
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npm install @gradial/aci@0.1.52-rc.
|
|
11
|
+
npm install @gradial/aci@0.1.52-rc.42 zod@^4
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
## Root Import
|
|
@@ -137,13 +137,13 @@ host bundles select and serve immutable release artifacts.
|
|
|
137
137
|
The first RC scaffold path is Next:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
-
npx @gradial/aci@0.1.52-rc.
|
|
140
|
+
npx @gradial/aci@0.1.52-rc.42 init my-site --template next-starter
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
List available templates:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
npx @gradial/aci@0.1.52-rc.
|
|
146
|
+
npx @gradial/aci@0.1.52-rc.42 init --list
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
## Personalization: The One-Tag Install
|
|
@@ -10,6 +10,47 @@ export declare function signIdentity(rawID: string, key: SigningKey): Promise<st
|
|
|
10
10
|
export declare function randomIdentity(random?: (length: number) => Uint8Array): string;
|
|
11
11
|
export declare function identityHashHex(namespace: string, value: string): Promise<string>;
|
|
12
12
|
export declare function verifyClaims(value: string, keys: Record<string, string>, now: Date): Promise<Record<string, unknown> | null>;
|
|
13
|
+
export declare function verifyClaimsEvidence(value: string, keys: Record<string, string>, now: Date): Promise<Record<string, unknown> | null>;
|
|
14
|
+
/**
|
|
15
|
+
* The minting path that signed an aci_claims value: 'aci' claims contain
|
|
16
|
+
* first-party memberships only; 'edge' claims are the minted first-party ∪
|
|
17
|
+
* external union and require a matching live b2 receipt on a
|
|
18
|
+
* provider-enabled release.
|
|
19
|
+
*/
|
|
20
|
+
export type ClaimsIssuer = 'aci' | 'edge';
|
|
21
|
+
/**
|
|
22
|
+
* Exposes the payload's `iss` marker. Malformed/unknown markers — and
|
|
23
|
+
* pre-0059 unmarked payloads — yield undefined; since the §6 cutover,
|
|
24
|
+
* verifyClaims rejects those payloads outright, so a verified payload always
|
|
25
|
+
* carries a marker. The marker identifies the minting path; it does not
|
|
26
|
+
* grant membership by itself.
|
|
27
|
+
*/
|
|
28
|
+
export declare function claimsIssuer(payload: Record<string, unknown> | null): ClaimsIssuer | undefined;
|
|
29
|
+
/** audience.MaxClaimsCookieBytes — the hard 1 KiB aci_claims budget. */
|
|
30
|
+
export declare const MAX_CLAIMS_COOKIE_BYTES = 1024;
|
|
31
|
+
/** audience.DefaultClaimsTTL — the 24-hour signed-lifetime ceiling. */
|
|
32
|
+
export declare const DEFAULT_CLAIMS_TTL_SECONDS: number;
|
|
33
|
+
/**
|
|
34
|
+
* Mint rejection: oversize, a malformed key, or a missing issuer marker.
|
|
35
|
+
* Callers fail closed on it — the edge never truncates or subsets
|
|
36
|
+
* memberships to fit (ADR 0059 §2/§3).
|
|
37
|
+
*/
|
|
38
|
+
export declare class ClaimsMintError extends Error {
|
|
39
|
+
readonly name = "ClaimsMintError";
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Mints one signed aci_claims value: v1.{kid}.{base64url(payload)}.{hmac},
|
|
43
|
+
* byte-identical to Go's ClaimsIssuer.IssueClaims — payload field order is
|
|
44
|
+
* aud (omitted when empty), seg (omitted when empty), iat, exp, iss, and the
|
|
45
|
+
* TTL clamps to the 24-hour ceiling. The exact bytes are pinned against the
|
|
46
|
+
* Go golden in claims_contract.test.ts. Issuance requires an explicit issuer
|
|
47
|
+
* marker; the marker identifies the minting path, it does not grant
|
|
48
|
+
* membership by itself.
|
|
49
|
+
*/
|
|
50
|
+
export declare function issueClaims(memberships: {
|
|
51
|
+
aud?: string[];
|
|
52
|
+
seg?: string[];
|
|
53
|
+
}, issuer: ClaimsIssuer, key: SigningKey, now: Date, ttlSeconds?: number): Promise<string>;
|
|
13
54
|
export declare function verifyHMAC(value: string, signature: string, secret: string): Promise<boolean>;
|
|
14
55
|
export declare function hmacSHA256(value: string, secret: string): Promise<string>;
|
|
15
56
|
export declare function base64URLEncode(bytes: Uint8Array): string;
|
|
@@ -149,7 +149,30 @@ function bytesToHex(bytes) {
|
|
|
149
149
|
return value;
|
|
150
150
|
}
|
|
151
151
|
// ── Claims cookie (aci_claims) ──
|
|
152
|
+
// verifyClaims is the PERSONALIZATION grade: signature, expiry, and the
|
|
153
|
+
// ADR 0059 §6 issuer-marker gate — a claim without a fresh marker is never
|
|
154
|
+
// trusted for membership selection. Existing signed cookies expire by their
|
|
155
|
+
// own TTL; their old contents are not read during the transition.
|
|
152
156
|
export async function verifyClaims(value, keys, now) {
|
|
157
|
+
const payload = await verifyClaimsAuthenticity(value, keys, now);
|
|
158
|
+
if (payload === null || claimsIssuer(payload) === undefined)
|
|
159
|
+
return null;
|
|
160
|
+
return payload;
|
|
161
|
+
}
|
|
162
|
+
// verifyClaimsEvidence is the EVIDENCE grade (anonymous-experiments REQ-6):
|
|
163
|
+
// signature and expiry WITHOUT the issuer gate. The collector's
|
|
164
|
+
// withdrawal/suppression trigger only needs proof that identity-tier state
|
|
165
|
+
// existed — an authentically signed, unexpired pre-cutover (unmarked) cookie
|
|
166
|
+
// is exactly that proof, and the Go collector accepts it the same way (Go
|
|
167
|
+
// ClaimsVerifier.VerifyClaims has no marker gate). Evidence never feeds
|
|
168
|
+
// membership selection, so the §6 gate does not apply here.
|
|
169
|
+
export async function verifyClaimsEvidence(value, keys, now) {
|
|
170
|
+
return verifyClaimsAuthenticity(value, keys, now);
|
|
171
|
+
}
|
|
172
|
+
// verifyClaimsAuthenticity is the shared core: envelope, keyed signature,
|
|
173
|
+
// and expiry — no policy gate. Every structural failure degrades to null
|
|
174
|
+
// (never an error), matching Go's no-oracle posture.
|
|
175
|
+
async function verifyClaimsAuthenticity(value, keys, now) {
|
|
153
176
|
const parts = value.trim().split('.');
|
|
154
177
|
if (parts.length !== 4 || parts[0] !== 'v1')
|
|
155
178
|
return null;
|
|
@@ -169,6 +192,67 @@ export async function verifyClaims(value, keys, now) {
|
|
|
169
192
|
return null;
|
|
170
193
|
}
|
|
171
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Exposes the payload's `iss` marker. Malformed/unknown markers — and
|
|
197
|
+
* pre-0059 unmarked payloads — yield undefined; since the §6 cutover,
|
|
198
|
+
* verifyClaims rejects those payloads outright, so a verified payload always
|
|
199
|
+
* carries a marker. The marker identifies the minting path; it does not
|
|
200
|
+
* grant membership by itself.
|
|
201
|
+
*/
|
|
202
|
+
export function claimsIssuer(payload) {
|
|
203
|
+
const iss = payload?.iss;
|
|
204
|
+
return iss === 'aci' || iss === 'edge' ? iss : undefined;
|
|
205
|
+
}
|
|
206
|
+
/** audience.MaxClaimsCookieBytes — the hard 1 KiB aci_claims budget. */
|
|
207
|
+
export const MAX_CLAIMS_COOKIE_BYTES = 1024;
|
|
208
|
+
/** audience.DefaultClaimsTTL — the 24-hour signed-lifetime ceiling. */
|
|
209
|
+
export const DEFAULT_CLAIMS_TTL_SECONDS = 24 * 60 * 60;
|
|
210
|
+
/**
|
|
211
|
+
* Mint rejection: oversize, a malformed key, or a missing issuer marker.
|
|
212
|
+
* Callers fail closed on it — the edge never truncates or subsets
|
|
213
|
+
* memberships to fit (ADR 0059 §2/§3).
|
|
214
|
+
*/
|
|
215
|
+
export class ClaimsMintError extends Error {
|
|
216
|
+
name = 'ClaimsMintError';
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Mints one signed aci_claims value: v1.{kid}.{base64url(payload)}.{hmac},
|
|
220
|
+
* byte-identical to Go's ClaimsIssuer.IssueClaims — payload field order is
|
|
221
|
+
* aud (omitted when empty), seg (omitted when empty), iat, exp, iss, and the
|
|
222
|
+
* TTL clamps to the 24-hour ceiling. The exact bytes are pinned against the
|
|
223
|
+
* Go golden in claims_contract.test.ts. Issuance requires an explicit issuer
|
|
224
|
+
* marker; the marker identifies the minting path, it does not grant
|
|
225
|
+
* membership by itself.
|
|
226
|
+
*/
|
|
227
|
+
export async function issueClaims(memberships, issuer, key, now, ttlSeconds) {
|
|
228
|
+
const kid = key.kid.trim();
|
|
229
|
+
if (!key.secret)
|
|
230
|
+
throw new ClaimsMintError('claims issuer requires a secret');
|
|
231
|
+
if (!kid)
|
|
232
|
+
throw new ClaimsMintError('claims issuer requires a kid');
|
|
233
|
+
if (kid.includes('.'))
|
|
234
|
+
throw new ClaimsMintError("claims kid must not contain '.'");
|
|
235
|
+
if (issuer !== 'aci' && issuer !== 'edge') {
|
|
236
|
+
throw new ClaimsMintError('claims issuer requires an explicit issuer marker');
|
|
237
|
+
}
|
|
238
|
+
const ttl = ttlSeconds === undefined || ttlSeconds <= 0 || ttlSeconds > DEFAULT_CLAIMS_TTL_SECONDS
|
|
239
|
+
? DEFAULT_CLAIMS_TTL_SECONDS
|
|
240
|
+
: Math.floor(ttlSeconds);
|
|
241
|
+
const iat = Math.floor(now.getTime() / 1000);
|
|
242
|
+
const body = JSON.stringify({
|
|
243
|
+
...(memberships.aud?.length ? { aud: memberships.aud } : {}),
|
|
244
|
+
...(memberships.seg?.length ? { seg: memberships.seg } : {}),
|
|
245
|
+
iat,
|
|
246
|
+
exp: iat + ttl,
|
|
247
|
+
iss: issuer,
|
|
248
|
+
});
|
|
249
|
+
const encoded = base64URLEncode(encoder.encode(body));
|
|
250
|
+
const value = `v1.${kid}.${encoded}.${await hmacSHA256(`v1.${kid}.${encoded}`, key.secret)}`;
|
|
251
|
+
if (encoder.encode(value).byteLength > MAX_CLAIMS_COOKIE_BYTES) {
|
|
252
|
+
throw new ClaimsMintError(`claims cookie exceeds the ${MAX_CLAIMS_COOKIE_BYTES}-byte budget (aud=${memberships.aud?.length ?? 0} seg=${memberships.seg?.length ?? 0})`);
|
|
253
|
+
}
|
|
254
|
+
return value;
|
|
255
|
+
}
|
|
172
256
|
// ── Internal crypto helpers ──
|
|
173
257
|
// verifyHMAC returns a verdict about the signature, which is the only visitor
|
|
174
258
|
// input here: a malformed or wrong signature is `false`. A fault importing the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradial/aci",
|
|
3
|
-
"version": "0.1.52-rc.
|
|
3
|
+
"version": "0.1.52-rc.42",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/gradial/bare-metal-go.git",
|
|
@@ -160,11 +160,11 @@
|
|
|
160
160
|
"zod": "^4.0.0"
|
|
161
161
|
},
|
|
162
162
|
"optionalDependencies": {
|
|
163
|
-
"@gradial/aci-cli-darwin-arm64": "0.1.52-rc.
|
|
164
|
-
"@gradial/aci-cli-darwin-x64": "0.1.52-rc.
|
|
165
|
-
"@gradial/aci-cli-linux-arm64": "0.1.52-rc.
|
|
166
|
-
"@gradial/aci-cli-linux-x64": "0.1.52-rc.
|
|
167
|
-
"@gradial/aci-cli-win32-arm64": "0.1.52-rc.
|
|
168
|
-
"@gradial/aci-cli-win32-x64": "0.1.52-rc.
|
|
163
|
+
"@gradial/aci-cli-darwin-arm64": "0.1.52-rc.42",
|
|
164
|
+
"@gradial/aci-cli-darwin-x64": "0.1.52-rc.42",
|
|
165
|
+
"@gradial/aci-cli-linux-arm64": "0.1.52-rc.42",
|
|
166
|
+
"@gradial/aci-cli-linux-x64": "0.1.52-rc.42",
|
|
167
|
+
"@gradial/aci-cli-win32-arm64": "0.1.52-rc.42",
|
|
168
|
+
"@gradial/aci-cli-win32-x64": "0.1.52-rc.42"
|
|
169
169
|
}
|
|
170
170
|
}
|