Skip to content

Commit 8136ae7

Browse files
boehlerlukasclaude
andauthored
feat: name the initialize key "Project ID"; accept { projectId }; version 19.6.0 (#209)
- index.d.ts: initialize(projectId, options) and initialize({ projectId, ... }) overloads, new Gleap.InitializeOptions type (disablePing marked deprecated). - Gleap.initialize accepts the Project ID positionally (unchanged), as options.projectId in a single options object, or in the second argument. - JSDoc, README and comments say Project ID; the value is the same key. - Tests for every initialize form. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1734a06 commit 8136ae7

8 files changed

Lines changed: 109 additions & 19 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 19.6.0
4+
Changed: the key `Gleap.initialize` takes is now called **Project ID** (formerly "SDK key" or "API key"). The value is the same and every existing key keeps working; nothing needs to change in your app. Typings, JSDoc and the README name the parameter `projectId`.
5+
Added: `Gleap.initialize({ projectId, sessionDuration })` takes the Project ID inside the options object, and `Gleap.initialize(undefined, { projectId })` works too. The positional form `Gleap.initialize(projectId, options)` and the legacy boolean second argument are unchanged. The options are typed as `Gleap.InitializeOptions`.
6+
37
## 19.5.2
48
Fixed: `Gleap.setUserJwtProvider` alone never signed the session again after a page reload. When the grant cookie was missing (an IP-address host, or the cookie deleted) and the app set only the provider, without calling `setUserJwt`, the user stayed unsigned although the server reported Signed mode. The SDK now asks the provider once per page load when the server reports Signed mode for an identified session without a valid grant and no token is held, and identifies with the returned token like `setUserJwt` (a token for another user goes through the usual `identity_mismatch` recovery). A provider that returns `null` sends nothing. Also applies when the provider is set after the session loaded.
59
Fixed: cookies were never stored on IP-address hosts (for example `http://127.0.0.1:8080` or `http://[::1]:8080`). The SDK wrote an invalid `domain` attribute there, so the browser dropped the session and grant cookies. On an IP address they are now host-only cookies (no `domain`), and erasing them works the same way. Domain hosts and `localhost` are unchanged.

‎README.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ import Gleap from 'gleap';
3232

3333
### Initialize the SDK
3434

35-
Add the following code to initialize the Gleap JavaScript SDK. Replace "SDK-TOKEN" with your actual SDK token from the [Gleap dashboard](https://app.gleap.io).
35+
Add the following code to initialize the Gleap JavaScript SDK. Replace "YOUR_PROJECT_ID" with your Project ID from the [Gleap dashboard](https://app.gleap.io) (Settings > Project). The Project ID was called "SDK key" or "API key" before; the value is the same and existing keys keep working.
3636

3737
```
38-
Gleap.initialize("SDK-TOKEN");
38+
Gleap.initialize("YOUR_PROJECT_ID");
3939
```
4040

4141
### Data region (optional)
@@ -44,7 +44,7 @@ Projects hosted in the US data region select it before initializing. The default
4444

4545
```
4646
Gleap.setRegion("us");
47-
Gleap.initialize("SDK-TOKEN");
47+
Gleap.initialize("YOUR_PROJECT_ID");
4848
```
4949

5050
### Identify your users
@@ -79,10 +79,10 @@ Per-user tokens for your API tools (used as `{{session.authTokens.<name>}}`) are
7979
Gleap.setAuthTokens({ backend: userAccessToken });
8080
```
8181

82-
A valid token signs the session: the server answers with a grant that the SDK sends as the `Gleap-Grant` header on every request and hands to the messenger. It is kept in memory and in the `gleap-grant-<SDK-TOKEN>` cookie on your top-level domain (unless `Gleap.setUseCookies(false)`; on an IP address such as `127.0.0.1` it is a host-only cookie), so a page reload and a help center on a subdomain stay signed until it expires. The project's session max age (Settings > Security, 7 days by default) sets its lifetime; shorten it per app with `sessionDuration` in milliseconds:
82+
A valid token signs the session: the server answers with a grant that the SDK sends as the `Gleap-Grant` header on every request and hands to the messenger. It is kept in memory and in the `gleap-grant-<YOUR_PROJECT_ID>` cookie on your top-level domain (unless `Gleap.setUseCookies(false)`; on an IP address such as `127.0.0.1` it is a host-only cookie), so a page reload and a help center on a subdomain stay signed until it expires. The project's session max age (Settings > Security, 7 days by default) sets its lifetime; shorten it per app with `sessionDuration` in milliseconds:
8383

8484
```
85-
Gleap.initialize("SDK-TOKEN", { sessionDuration: 24 * 60 * 60 * 1000 });
85+
Gleap.initialize("YOUR_PROJECT_ID", { sessionDuration: 24 * 60 * 60 * 1000 });
8686
```
8787

8888
or later with `Gleap.setSessionDuration(24 * 60 * 60 * 1000)` (the same call as in the mobile SDKs).

‎index.d.ts‎

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,39 @@
22
export type GleapRegion = "eu" | "us";
33

44
export namespace Gleap {
5+
/** Options for `initialize`. */
6+
interface InitializeOptions {
7+
/**
8+
* Your Project ID (Gleap dashboard: Settings > Project, or the install page).
9+
* Only needed when `initialize` is called with the options object alone.
10+
*/
11+
projectId?: string;
12+
/**
13+
* How long (ms) a signed session stays signed before a new identify is needed.
14+
* The server never goes beyond the project's session max age.
15+
*/
16+
sessionDuration?: number;
17+
/** @deprecated Has no effect: the ping it controlled no longer exists. */
18+
disablePing?: boolean;
19+
}
520
/**
21+
* Initializes Gleap with your Project ID (formerly called "SDK key" or "API key";
22+
* the value is the same, existing keys keep working).
23+
*
624
* `options.sessionDuration`: how long (ms) a signed session stays signed before a new
725
* identify is needed. The server never goes beyond the project's session max age.
826
* A boolean second argument is the legacy `disablePing` flag and is still accepted
927
* (the ping it controlled no longer exists, so it has no effect).
28+
*
29+
* @example Gleap.initialize("YOUR_PROJECT_ID");
30+
* @example Gleap.initialize({ projectId: "YOUR_PROJECT_ID", sessionDuration: 86400000 });
1031
*/
1132
function initialize(
12-
sdkKey: string,
13-
options?: boolean | { disablePing?: boolean; sessionDuration?: number }
33+
projectId: string,
34+
options?: boolean | InitializeOptions
35+
): void;
36+
function initialize(
37+
options: InitializeOptions & { projectId: string }
1438
): void;
1539
function sendSilentCrashReport(
1640
description: string,
@@ -200,7 +224,7 @@ export namespace Gleap {
200224
function setUserJwtProvider(provider: (() => string | null | Promise<string | null>) | null): void;
201225
/**
202226
* How long (ms) a signed session stays signed; the server never goes beyond the
203-
* project's maximum. Same as `initialize(sdkKey, { sessionDuration })`. `null` drops it.
227+
* project's maximum. Same as `initialize(projectId, { sessionDuration })`. `null` drops it.
204228
*/
205229
function setSessionDuration(sessionDuration: number | null): void;
206230
/**

‎package-lock.json‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"description": "JavaScript and TypeScript SDK for Gleap, an Intercom alternative with AI customer support, live chat, in-app bug reporting and customer feedback.",
33
"name": "gleap",
4-
"version": "19.5.2",
4+
"version": "19.6.0",
55
"main": "build/cjs/index.js",
66
"module": "build/esm/index.mjs",
77
"exports": {

‎src/Gleap.js‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,20 +235,30 @@ class Gleap {
235235
}
236236

237237
/**
238-
* Initializes the SDK
239-
* @param {*} sdkKey
240-
* @param {boolean | { disablePing?: boolean, sessionDuration?: number }} [options]
238+
* Initializes the SDK with your Project ID (formerly called "SDK key"; the value is
239+
* the same, existing keys keep working).
240+
* @param {string | { projectId: string, sessionDuration?: number }} projectId
241+
* The Project ID, or an options object that carries it as `projectId`.
242+
* @param {boolean | { projectId?: string, disablePing?: boolean, sessionDuration?: number }} [options]
241243
* sessionDuration: how long (ms) a signed session stays signed; the server never goes
242244
* beyond the project's maximum. A boolean (the legacy `disablePing` argument) and
243245
* `disablePing` are accepted and have no effect: the ping no longer exists.
244246
*/
245-
static initialize(sdkKey, options) {
247+
static initialize(projectId, options) {
246248
const instance = this.getInstance();
247249
if (instance.initialized) {
248250
console.warn('Gleap already initialized.');
249251
return;
250252
}
251253

254+
// Gleap.initialize({ projectId, ...options })
255+
if (projectId && typeof projectId === 'object') {
256+
options = projectId;
257+
projectId = options.projectId;
258+
} else if (!projectId && options && typeof options === 'object' && options.projectId) {
259+
projectId = options.projectId;
260+
}
261+
252262
if (options && typeof options === 'object' && 'sessionDuration' in options) {
253263
GleapSession.getInstance().setSessionDuration(options.sessionDuration);
254264
}
@@ -273,7 +283,7 @@ class Gleap {
273283

274284
// Start session
275285
const sessionInstance = GleapSession.getInstance();
276-
sessionInstance.sdkKey = sdkKey;
286+
sessionInstance.sdkKey = projectId;
277287
sessionInstance.setOnSessionReady(() => {
278288
// Run auto configuration.
279289
setTimeout(() => {
@@ -498,7 +508,7 @@ class Gleap {
498508
/**
499509
* How long (ms) a signed session stays signed; the server never goes beyond
500510
* the project's maximum. Sent with every identify. `null` drops it.
501-
* Same as `initialize(sdkKey, { sessionDuration })`.
511+
* Same as `initialize(projectId, { sessionDuration })`.
502512
* @param {number | null} sessionDuration
503513
*/
504514
static setSessionDuration(sessionDuration) {

‎src/GleapInitialize.test.js‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @jest-environment jsdom
3+
*/
4+
import Gleap, { GleapSession } from './Gleap';
5+
6+
// initialize() names the key "Project ID"; the positional form keeps working.
7+
describe('Gleap.initialize(projectId)', () => {
8+
let startSpy;
9+
let warnSpy;
10+
11+
beforeEach(() => {
12+
Gleap.getInstance().initialized = false;
13+
GleapSession.instance = undefined;
14+
// startSession is an instance arrow property: stub it on the fresh singleton.
15+
startSpy = jest.spyOn(GleapSession.getInstance(), 'startSession').mockImplementation(() => {});
16+
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
17+
});
18+
19+
afterEach(() => {
20+
startSpy.mockRestore();
21+
warnSpy.mockRestore();
22+
Gleap.getInstance().initialized = false;
23+
});
24+
25+
test('positional Project ID (the former SDK key) is used as before', () => {
26+
Gleap.initialize('PROJECT_ID_1');
27+
expect(GleapSession.getInstance().sdkKey).toBe('PROJECT_ID_1');
28+
expect(startSpy).toHaveBeenCalledTimes(1);
29+
});
30+
31+
test('positional Project ID with options keeps sessionDuration', () => {
32+
Gleap.initialize('PROJECT_ID_2', { sessionDuration: 60000 });
33+
expect(GleapSession.getInstance().sdkKey).toBe('PROJECT_ID_2');
34+
expect(GleapSession.getInstance().sessionDuration).toBe(60000);
35+
});
36+
37+
test('legacy boolean second argument is still accepted', () => {
38+
Gleap.initialize('PROJECT_ID_3', true);
39+
expect(GleapSession.getInstance().sdkKey).toBe('PROJECT_ID_3');
40+
});
41+
42+
test('options object with projectId', () => {
43+
Gleap.initialize({ projectId: 'PROJECT_ID_4', sessionDuration: 120000 });
44+
expect(GleapSession.getInstance().sdkKey).toBe('PROJECT_ID_4');
45+
expect(GleapSession.getInstance().sessionDuration).toBe(120000);
46+
});
47+
48+
test('projectId in the second argument when the first is empty', () => {
49+
Gleap.initialize(undefined, { projectId: 'PROJECT_ID_5' });
50+
expect(GleapSession.getInstance().sdkKey).toBe('PROJECT_ID_5');
51+
});
52+
});

‎src/GleapSession.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export default class GleapSession {
112112
// How the last identify failed ('refused' when a refusal was logged, else
113113
// 'network error' / 'HTTP <status>'), for setUserJwt's log line.
114114
lastIdentifyFailure = null;
115-
// Gleap.initialize(sdkKey, { sessionDuration }): asks the server for a
115+
// Gleap.initialize(projectId, { sessionDuration }): asks the server for a
116116
// shorter grant (ms). Sent with every identify.
117117
sessionDuration = null;
118118
// Bumped only by clearSession (logout, destroy, rejected session). An
@@ -1457,7 +1457,7 @@ export default class GleapSession {
14571457
return retry;
14581458
};
14591459

1460-
/** Gleap.setSessionDuration / initialize(sdkKey, { sessionDuration }): a positive number of milliseconds, or null to drop it. */
1460+
/** Gleap.setSessionDuration / initialize(projectId, { sessionDuration }): a positive number of milliseconds, or null to drop it. */
14611461
setSessionDuration = (sessionDuration) => {
14621462
if (sessionDuration === undefined || sessionDuration === null) {
14631463
this.sessionDuration = null;

0 commit comments

Comments
 (0)