@north-light/sdk 0.3.539 → 0.3.541
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/dist/error-codes.js +1 -1
- package/dist/oauth/index.d.ts +7 -5
- package/dist/oauth/index.js +15 -9
- package/dist/skill/northlight/SKILL.md +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/error-codes.js
CHANGED
|
@@ -11,7 +11,7 @@ export const sdkErrorCodes = [
|
|
|
11
11
|
'oauth_nonce_missing',
|
|
12
12
|
/** The callback's `state` was missing or differed from the saved one. */
|
|
13
13
|
'oauth_state_mismatch',
|
|
14
|
-
/** `exchangeCode` got a sign-in-only answer
|
|
14
|
+
/** `exchangeCode` got a sign-in-only answer (no connection); finish such a sign-in with `exchangeIdentity`. */
|
|
15
15
|
'oauth_exchange_mismatch',
|
|
16
16
|
/** `oauth.client(userId)` or `refresh` found no stored connection for the person: they must sign in again. */
|
|
17
17
|
'not_connected',
|
package/dist/oauth/index.d.ts
CHANGED
|
@@ -188,11 +188,12 @@ export declare class OAuth2Client {
|
|
|
188
188
|
nonce?: string;
|
|
189
189
|
}): Promise<Connection>;
|
|
190
190
|
/**
|
|
191
|
-
* Finish a sign-in-only request (`authorizeUrl` with scopes `openid
|
|
192
|
-
* person's verified identity.
|
|
193
|
-
* `nonce` is the value `authorizeUrl` returned and is required. A response without an ID token, or with
|
|
194
|
-
*
|
|
195
|
-
*
|
|
191
|
+
* Finish a sign-in-only request (`authorizeUrl` with scopes `openid`, optionally with `email` and `profile`) and
|
|
192
|
+
* return the person's verified identity. The app gets no connection, refresh token, or runtime access on this path.
|
|
193
|
+
* `nonce` is the value `authorizeUrl` returned and is required. A response without an ID token, or with one that
|
|
194
|
+
* fails verification, throws `id_token_invalid`. The directory may still answer with a runtime connection (it gives
|
|
195
|
+
* one on every sign-in to an app held by a team with a runtime grant); the identity is returned all the same, and
|
|
196
|
+
* the unneeded refresh token is revoked best-effort. Revocation removes only that token, never the grant.
|
|
196
197
|
*/
|
|
197
198
|
exchangeIdentity({ code, codeVerifier, state, expectedState, nonce }: {
|
|
198
199
|
code: string;
|
|
@@ -271,6 +272,7 @@ export declare class OAuth2Client {
|
|
|
271
272
|
nonce?: string;
|
|
272
273
|
}): Promise<IdTokenClaims>;
|
|
273
274
|
revoke(connection: Connection): Promise<boolean>;
|
|
275
|
+
private revokeRefreshToken;
|
|
274
276
|
/** A token request. `deadlineAt` is the whole operation's deadline (discovery included); without one it starts now. */
|
|
275
277
|
private tokenResponse;
|
|
276
278
|
private connectionFrom;
|
package/dist/oauth/index.js
CHANGED
|
@@ -265,23 +265,26 @@ export class OAuth2Client {
|
|
|
265
265
|
return connection;
|
|
266
266
|
}
|
|
267
267
|
/**
|
|
268
|
-
* Finish a sign-in-only request (`authorizeUrl` with scopes `openid
|
|
269
|
-
* person's verified identity.
|
|
270
|
-
* `nonce` is the value `authorizeUrl` returned and is required. A response without an ID token, or with
|
|
271
|
-
*
|
|
272
|
-
*
|
|
268
|
+
* Finish a sign-in-only request (`authorizeUrl` with scopes `openid`, optionally with `email` and `profile`) and
|
|
269
|
+
* return the person's verified identity. The app gets no connection, refresh token, or runtime access on this path.
|
|
270
|
+
* `nonce` is the value `authorizeUrl` returned and is required. A response without an ID token, or with one that
|
|
271
|
+
* fails verification, throws `id_token_invalid`. The directory may still answer with a runtime connection (it gives
|
|
272
|
+
* one on every sign-in to an app held by a team with a runtime grant); the identity is returned all the same, and
|
|
273
|
+
* the unneeded refresh token is revoked best-effort. Revocation removes only that token, never the grant.
|
|
273
274
|
*/
|
|
274
275
|
async exchangeIdentity({ code, codeVerifier, state, expectedState, nonce }) {
|
|
275
276
|
assertState(state, expectedState);
|
|
276
277
|
if (typeof nonce !== 'string' || !nonce)
|
|
277
278
|
throw new CrouterError('exchangeIdentity requires the nonce authorizeUrl returned', 'oauth_nonce_missing');
|
|
278
279
|
const response = await this.tokenResponse({ grant_type: 'authorization_code', code, redirect_uri: this.options.redirectUri, code_verifier: codeVerifier });
|
|
279
|
-
if (response.refresh_token !== undefined || response.runtimeUrl !== undefined) {
|
|
280
|
-
throw new CrouterError('The directory answered with a runtime connection, so the request asked for runtime scopes; finish it with exchangeCode(), or request only openid or openid email for a sign-in-only visitor', 'oauth_exchange_mismatch');
|
|
281
|
-
}
|
|
282
280
|
if (typeof response.id_token !== 'string' || !response.id_token)
|
|
283
281
|
throw new CrouterError('Directory returned no ID token for a sign-in-only request', 'id_token_invalid');
|
|
284
282
|
const claims = await this.verifyIdToken(response.id_token, { nonce });
|
|
283
|
+
if (typeof response.refresh_token === 'string' && response.refresh_token) {
|
|
284
|
+
// The directory gave a connection this sign-in does not use: drop its refresh token. Best-effort, because the
|
|
285
|
+
// identity is already verified and the token is unusable without the app's key.
|
|
286
|
+
await this.revokeRefreshToken(response.refresh_token).catch(() => undefined);
|
|
287
|
+
}
|
|
285
288
|
return {
|
|
286
289
|
sub: claims.sub,
|
|
287
290
|
...(typeof claims['email'] === 'string' ? { email: claims['email'] } : {}),
|
|
@@ -523,11 +526,14 @@ export class OAuth2Client {
|
|
|
523
526
|
return claims;
|
|
524
527
|
}
|
|
525
528
|
async revoke(connection) {
|
|
529
|
+
return await this.revokeRefreshToken(connection.refreshToken);
|
|
530
|
+
}
|
|
531
|
+
async revokeRefreshToken(refreshToken) {
|
|
526
532
|
const deadlineAt = Date.now() + this.timeoutMs;
|
|
527
533
|
const metadata = await this.discoveryWithin(deadlineAt);
|
|
528
534
|
if (!metadata.revocation_endpoint)
|
|
529
535
|
return false;
|
|
530
|
-
await this.post(metadata.revocation_endpoint, { token:
|
|
536
|
+
await this.post(metadata.revocation_endpoint, { token: refreshToken, token_type_hint: 'refresh_token' }, true, deadlineAt);
|
|
531
537
|
return true;
|
|
532
538
|
}
|
|
533
539
|
/** A token request. `deadlineAt` is the whole operation's deadline (discovery included); without one it starts now. */
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: northlight
|
|
3
3
|
description: "Use when building, debugging or shipping an app that signs people in with Northlight, starts runs on their Northlight runtime, or calls Northlight providers (sms, search, integrations, context, device) with @north-light/sdk."
|
|
4
4
|
metadata:
|
|
5
|
-
sdk-version: "0.3.
|
|
5
|
+
sdk-version: "0.3.541"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Building a Northlight app
|
|
@@ -11,7 +11,7 @@ An app on Northlight signs people in with their Northlight account, then starts
|
|
|
11
11
|
|
|
12
12
|
## First: check this skill matches the SDK
|
|
13
13
|
|
|
14
|
-
This skill is for SDK version `0.3.
|
|
14
|
+
This skill is for SDK version `0.3.541`. If the project has `node_modules/@north-light/sdk/package.json`, compare its `version` with that number. If they differ, run `npx @north-light/sdk skill` in the project, then read the rewritten `.agents/skills/northlight/SKILL.md` (or `.claude/skills/northlight/SKILL.md`) instead of this copy. That command needs no account and no crtr. A project that has no SDK yet starts with `npx @north-light/sdk@latest init <dir>`.
|
|
15
15
|
|
|
16
16
|
## Where things run
|
|
17
17
|
|
package/dist/version.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** This SDK's release version. Informational only: compatibility is the contract level, not this number. */
|
|
2
|
-
export declare const SDK_VERSION = "0.3.
|
|
2
|
+
export declare const SDK_VERSION = "0.3.541";
|
|
3
3
|
/** The release sent in `Crouter-Minimum-Runtime-Version` on every request. It is frozen, so a runtime from before the
|
|
4
4
|
* contract level existed (which only knows this header) refuses this SDK, while every later runtime accepts it. */
|
|
5
5
|
export declare const LEGACY_FLOOR = "0.3.423";
|
package/dist/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SDK_VERSION is written by scripts/release-version.mjs on every release; do not edit by hand.
|
|
2
2
|
/** This SDK's release version. Informational only: compatibility is the contract level, not this number. */
|
|
3
|
-
export const SDK_VERSION = '0.3.
|
|
3
|
+
export const SDK_VERSION = '0.3.541';
|
|
4
4
|
// LEGACY_FLOOR is written once by `scripts/contract.mjs release`, at the first release that carries the contract level
|
|
5
5
|
// (the `0.0.0` placeholder is replaced there and never again); do not edit by hand.
|
|
6
6
|
/** The release sent in `Crouter-Minimum-Runtime-Version` on every request. It is frozen, so a runtime from before the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.541",
|
|
4
4
|
"crouterContract": "1.28",
|
|
5
5
|
"description": "Typed Node and browser client for running crouter agents through the crtrd /v1 API.",
|
|
6
6
|
"type": "module",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"prepublishOnly": "node -e \"if (process.env.npm_config_tag !== 'next') { console.error('@north-light/sdk publishes only with --tag next; scripts/promote-sdk.mjs is the only mover of latest.'); process.exit(1); }\""
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@north-light/api": "0.3.
|
|
48
|
-
"@north-light/identity": "0.3.
|
|
47
|
+
"@north-light/api": "0.3.541",
|
|
48
|
+
"@north-light/identity": "0.3.541",
|
|
49
49
|
"jose": "^6.2.1"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|