@gitkraken/core-gitlens 0.24.0 → 0.26.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/CHANGELOG.md +40 -1
- package/README.md +23 -15
- package/dist/git/errors.d.ts +6 -5
- package/dist/git/errors.js +7 -6
- package/dist/git/errors.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.js +1 -1
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/remoteProvider.d.ts +4 -1
- package/dist/git/models/remoteProvider.js.map +1 -1
- package/dist/git/providers/operations.d.ts +15 -0
- package/dist/git/providers/provider.d.ts +4 -2
- package/dist/git/utils/branch.utils.d.ts +4 -1
- package/dist/git/utils/branch.utils.js +5 -2
- package/dist/git/utils/branch.utils.js.map +1 -1
- package/dist/git/utils/mergeConflicts.utils.js +2 -2
- package/dist/git/utils/mergeConflicts.utils.js.map +1 -1
- package/dist/git/watching/worktreeSummary.d.ts +15 -3
- package/dist/git/watching/worktreeSummary.js +179 -31
- package/dist/git/watching/worktreeSummary.js.map +1 -1
- package/dist/git-cli/cliGitProvider.d.ts +30 -3
- package/dist/git-cli/cliGitProvider.js +102 -40
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +9 -1
- package/dist/git-cli/exec/git.js +23 -4
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitDirResolver.d.ts +26 -0
- package/dist/git-cli/exec/gitDirResolver.js +181 -0
- package/dist/git-cli/exec/gitDirResolver.js.map +1 -0
- package/dist/git-cli/exec/headState.js +3 -3
- package/dist/git-cli/exec/headState.js.map +1 -1
- package/dist/git-cli/exec/indexRefresh.d.ts +78 -0
- package/dist/git-cli/exec/indexRefresh.js +159 -0
- package/dist/git-cli/exec/indexRefresh.js.map +1 -0
- package/dist/git-cli/providers/branchRemote.js +2 -5
- package/dist/git-cli/providers/branchRemote.js.map +1 -1
- package/dist/git-cli/providers/branches.js +4 -4
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +2 -0
- package/dist/git-cli/providers/config.js +26 -4
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/maintenance.js +1 -1
- package/dist/git-cli/providers/operations.d.ts +4 -1
- package/dist/git-cli/providers/operations.js +33 -25
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
- package/dist/git-cli/providers/pausedOperations.js +10 -7
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.js +25 -1
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/staging.js +1 -1
- package/dist/git-cli/providers/stash.d.ts +3 -1
- package/dist/git-cli/providers/stash.js +8 -5
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +6 -1
- package/dist/git-cli/providers/worktrees.js +6 -2
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.d.ts +2 -0
- package/dist/git-cli/service.js +2 -1
- package/dist/git-cli/service.js.map +1 -1
- package/dist/ipc/discovery.js +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/ai/errors.d.ts +4 -1
- package/dist/plus/ai/errors.js +4 -0
- package/dist/plus/ai/errors.js.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.js +1 -1
- package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +2 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/git-github/api/github.js +12 -13
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/api/token.d.ts +2 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +1 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.js +6 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -1
- package/dist/plus/integrations/authentication/configuredIntegrationService.js +2 -2
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +18 -5
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -1
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +3 -1
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js +4 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -1
- package/dist/plus/integrations/authentication/models.d.ts +2 -0
- package/dist/plus/integrations/authentication/models.js +2 -1
- package/dist/plus/integrations/authentication/models.js.map +1 -1
- package/dist/plus/integrations/authentication/observedAuthenticationProvider.js +1 -1
- package/dist/plus/integrations/authentication/rejectedTokenTracker.d.ts +5 -4
- package/dist/plus/integrations/authentication/rejectedTokenTracker.js +5 -4
- package/dist/plus/integrations/authentication/rejectedTokenTracker.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +2 -2
- package/dist/plus/integrations/index.js +1 -1
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +6 -0
- package/dist/plus/integrations/integrationService.js +3 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/lite.js +1 -1
- package/dist/plus/integrations/manager.d.ts +51 -3
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +14 -0
- package/dist/plus/integrations/models/gitHostIntegration.js +50 -41
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +27 -5
- package/dist/plus/integrations/models/integration.js +57 -15
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issueReads.d.ts +6 -0
- package/dist/plus/integrations/models/issuesIntegration.js +11 -11
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +2 -2
- package/dist/plus/integrations/providers/azureDevOps.js +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.js +1 -1
- package/dist/plus/integrations/providers/bitbucket.js +1 -1
- package/dist/plus/integrations/providers/github.js +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.js +2 -2
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js +1 -1
- package/dist/plus/integrations/providers/jira-server.js +2 -2
- package/dist/plus/integrations/providers/jira.js +1 -1
- package/dist/plus/integrations/providers/linear.js +2 -2
- package/dist/plus/integrations/providers/linear.js.map +1 -1
- package/dist/plus/integrations/providers/models.js +2 -1
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.js +9 -0
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.js +1 -1
- package/dist/plus/integrations/providers/trello.js +1 -1
- package/dist/plus/integrations/providers/utils.js +1 -1
- package/dist/plus/integrations/reads/counts.js +1 -1
- package/dist/plus/integrations/reads/cursors.js +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +5 -4
- package/dist/plus/integrations/reads/drains.js +28 -8
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +1 -1
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +1 -1
- package/dist/plus/integrations/reads/issues.d.ts +2 -0
- package/dist/plus/integrations/reads/issues.js +5 -3
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/paging.d.ts +5 -6
- package/dist/plus/integrations/reads/paging.js +5 -6
- package/dist/plus/integrations/reads/paging.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.d.ts +4 -0
- package/dist/plus/integrations/reads/pullRequests.js +4 -2
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js +42 -10
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +23 -3
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/plus/notifications/api.d.ts +20 -0
- package/dist/plus/notifications/api.js +89 -0
- package/dist/plus/notifications/api.js.map +1 -0
- package/dist/plus/notifications/context.d.ts +28 -0
- package/dist/plus/notifications/context.js +0 -0
- package/dist/plus/notifications/errors.d.ts +13 -0
- package/dist/plus/notifications/errors.js +22 -0
- package/dist/plus/notifications/errors.js.map +1 -0
- package/dist/plus/notifications/models.d.ts +94 -0
- package/dist/plus/notifications/models.js +0 -0
- package/dist/plus/notifications/notificationsService.d.ts +115 -0
- package/dist/plus/notifications/notificationsService.js +381 -0
- package/dist/plus/notifications/notificationsService.js.map +1 -0
- package/dist/plus/notifications/parse.d.ts +12 -0
- package/dist/plus/notifications/parse.js +152 -0
- package/dist/plus/notifications/parse.js.map +1 -0
- package/dist/plus/notifications/presentation.d.ts +28 -0
- package/dist/plus/notifications/presentation.js +55 -0
- package/dist/plus/notifications/presentation.js.map +1 -0
- package/dist/utils/env/node/exec.d.ts +10 -1
- package/dist/utils/env/node/exec.js +41 -4
- package/dist/utils/env/node/exec.js.map +1 -1
- package/docs/integrations.md +21 -2
- package/docs/notifications.md +239 -0
- package/package.json +21 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { NotificationsApiError } from "./errors.js";
|
|
2
|
+
import { isRecord, parseNotification } from "./parse.js";
|
|
3
|
+
//#region ../plus/notifications/src/api.ts
|
|
4
|
+
const notificationsPageSize = 50;
|
|
5
|
+
/** A thin client over the `notifications-service-v2` v1 API. */
|
|
6
|
+
var NotificationsApi = class {
|
|
7
|
+
context;
|
|
8
|
+
constructor(context) {
|
|
9
|
+
this.context = context;
|
|
10
|
+
}
|
|
11
|
+
/** Loads one page (1-based), newest first. Invalid notifications are dropped (and logged). */
|
|
12
|
+
async list(page, pageSize = 50) {
|
|
13
|
+
const query = new URLSearchParams({
|
|
14
|
+
productType: this.context.productType,
|
|
15
|
+
page: String(page),
|
|
16
|
+
pageSize: String(pageSize)
|
|
17
|
+
});
|
|
18
|
+
const data = await this.request("list", "v1/notifications", { method: "GET" }, query);
|
|
19
|
+
const results = isRecord(data) && Array.isArray(data.results) ? data.results : [];
|
|
20
|
+
const items = [];
|
|
21
|
+
for (const raw of results) {
|
|
22
|
+
const notification = parseNotification(raw, this.context.log);
|
|
23
|
+
if (notification != null) items.push(notification);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
items,
|
|
27
|
+
hasMore: isRecord(data) && data.hasMore === true,
|
|
28
|
+
page: isRecord(data) && typeof data.page === "number" ? data.page : page
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async markRead(ids) {
|
|
32
|
+
await this.request("markRead", "v1/notifications/read", {
|
|
33
|
+
method: "POST",
|
|
34
|
+
body: JSON.stringify({ notificationIds: ids })
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async markUnread(ids) {
|
|
38
|
+
await this.request("markUnread", "v1/notifications/unread", {
|
|
39
|
+
method: "POST",
|
|
40
|
+
body: JSON.stringify({ notificationIds: ids })
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async delete(ids) {
|
|
44
|
+
await this.request("delete", "v1/notifications", {
|
|
45
|
+
method: "DELETE",
|
|
46
|
+
body: JSON.stringify({ notificationIds: ids })
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async getSettings() {
|
|
50
|
+
const data = await this.request("getSettings", "v1/notifications/user-settings", { method: "GET" });
|
|
51
|
+
const settings = isRecord(data) ? data : {};
|
|
52
|
+
return {
|
|
53
|
+
marketingEnabled: settings.marketingEnabled !== false,
|
|
54
|
+
helpEnabled: settings.helpEnabled !== false,
|
|
55
|
+
securityEnabled: settings.securityEnabled !== false
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async updateSettings(settings) {
|
|
59
|
+
await this.request("updateSettings", "v1/notifications/user-settings", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
marketingEnabled: settings.marketingEnabled,
|
|
63
|
+
helpEnabled: settings.helpEnabled,
|
|
64
|
+
securityEnabled: settings.securityEnabled
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Sends the request and returns the unwrapped `data` envelope (or `undefined` for an empty body). */
|
|
69
|
+
async request(operation, path, init, query) {
|
|
70
|
+
const rsp = await this.context.fetchGkApi(path, {
|
|
71
|
+
...init,
|
|
72
|
+
headers: { "Content-Type": "application/json" }
|
|
73
|
+
}, query);
|
|
74
|
+
if (!rsp.ok) throw new NotificationsApiError(rsp.status, operation, rsp.statusText);
|
|
75
|
+
const text = await rsp.text();
|
|
76
|
+
if (!text) return void 0;
|
|
77
|
+
let json;
|
|
78
|
+
try {
|
|
79
|
+
json = JSON.parse(text);
|
|
80
|
+
} catch (ex) {
|
|
81
|
+
throw new NotificationsApiError(rsp.status, operation, "invalid JSON response", { cause: ex });
|
|
82
|
+
}
|
|
83
|
+
return isRecord(json) ? json.data ?? json : json;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
export { NotificationsApi, notificationsPageSize };
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../../../plus/notifications/src/api.ts"],"sourcesContent":["import type { NotificationsContext } from './context.js';\nimport { NotificationsApiError } from './errors.js';\nimport type { GkNotification, NotificationSettings, NotificationsPage } from './models.js';\nimport { isRecord, parseNotification } from './parse.js';\n\nexport const notificationsPageSize = 50;\n\n/** A thin client over the `notifications-service-v2` v1 API. */\nexport class NotificationsApi {\n\tconstructor(private readonly context: NotificationsContext) {}\n\n\t/** Loads one page (1-based), newest first. Invalid notifications are dropped (and logged). */\n\tasync list(page: number, pageSize: number = notificationsPageSize): Promise<NotificationsPage> {\n\t\tconst query = new URLSearchParams({\n\t\t\tproductType: this.context.productType,\n\t\t\tpage: String(page),\n\t\t\tpageSize: String(pageSize),\n\t\t});\n\t\tconst data = await this.request('list', 'v1/notifications', { method: 'GET' }, query);\n\n\t\tconst results = isRecord(data) && Array.isArray(data.results) ? (data.results as unknown[]) : [];\n\t\tconst items: GkNotification[] = [];\n\t\tfor (const raw of results) {\n\t\t\tconst notification = parseNotification(raw, this.context.log);\n\t\t\tif (notification != null) {\n\t\t\t\titems.push(notification);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\titems: items,\n\t\t\thasMore: isRecord(data) && data.hasMore === true,\n\t\t\tpage: isRecord(data) && typeof data.page === 'number' ? data.page : page,\n\t\t};\n\t}\n\n\tasync markRead(ids: readonly string[]): Promise<void> {\n\t\tawait this.request('markRead', 'v1/notifications/read', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: JSON.stringify({ notificationIds: ids }),\n\t\t});\n\t}\n\n\tasync markUnread(ids: readonly string[]): Promise<void> {\n\t\tawait this.request('markUnread', 'v1/notifications/unread', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: JSON.stringify({ notificationIds: ids }),\n\t\t});\n\t}\n\n\tasync delete(ids: readonly string[]): Promise<void> {\n\t\tawait this.request('delete', 'v1/notifications', {\n\t\t\tmethod: 'DELETE',\n\t\t\tbody: JSON.stringify({ notificationIds: ids }),\n\t\t});\n\t}\n\n\tasync getSettings(): Promise<NotificationSettings> {\n\t\tconst data = await this.request('getSettings', 'v1/notifications/user-settings', { method: 'GET' });\n\t\tconst settings = isRecord(data) ? data : {};\n\t\t// A missing flag means the service default, which is opted in\n\t\treturn {\n\t\t\tmarketingEnabled: settings.marketingEnabled !== false,\n\t\t\thelpEnabled: settings.helpEnabled !== false,\n\t\t\tsecurityEnabled: settings.securityEnabled !== false,\n\t\t};\n\t}\n\n\tasync updateSettings(settings: NotificationSettings): Promise<void> {\n\t\tawait this.request('updateSettings', 'v1/notifications/user-settings', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmarketingEnabled: settings.marketingEnabled,\n\t\t\t\thelpEnabled: settings.helpEnabled,\n\t\t\t\tsecurityEnabled: settings.securityEnabled,\n\t\t\t} satisfies NotificationSettings),\n\t\t});\n\t}\n\n\t/** Sends the request and returns the unwrapped `data` envelope (or `undefined` for an empty body). */\n\tprivate async request(\n\t\toperation: string,\n\t\tpath: string,\n\t\tinit: RequestInit,\n\t\tquery?: URLSearchParams,\n\t): Promise<unknown> {\n\t\tconst rsp = await this.context.fetchGkApi(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...init,\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t},\n\t\t\tquery,\n\t\t);\n\t\tif (!rsp.ok) throw new NotificationsApiError(rsp.status, operation, rsp.statusText);\n\n\t\tconst text = await rsp.text();\n\t\tif (!text) return undefined;\n\n\t\tlet json: unknown;\n\t\ttry {\n\t\t\tjson = JSON.parse(text);\n\t\t} catch (ex) {\n\t\t\tthrow new NotificationsApiError(rsp.status, operation, 'invalid JSON response', { cause: ex });\n\t\t}\n\t\treturn isRecord(json) ? (json.data ?? json) : json;\n\t}\n}\n"],"mappings":";;;AAKA,MAAa,wBAAwB;;AAGrC,IAAa,mBAAb,MAA8B;CACA;CAA7B,YAAY,SAAgD;EAA/B,KAAA,UAAA;CAAgC;;CAG7D,MAAM,KAAK,MAAc,WAAA,IAAsE;EAC9F,MAAM,QAAQ,IAAI,gBAAgB;GACjC,aAAa,KAAK,QAAQ;GAC1B,MAAM,OAAO,IAAI;GACjB,UAAU,OAAO,QAAQ;EAC1B,CAAC;EACD,MAAM,OAAO,MAAM,KAAK,QAAQ,QAAQ,oBAAoB,EAAE,QAAQ,MAAM,GAAG,KAAK;EAEpF,MAAM,UAAU,SAAS,IAAI,KAAK,MAAM,QAAQ,KAAK,OAAO,IAAK,KAAK,UAAwB,CAAC;EAC/F,MAAM,QAA0B,CAAC;EACjC,KAAK,MAAM,OAAO,SAAS;GAC1B,MAAM,eAAe,kBAAkB,KAAK,KAAK,QAAQ,GAAG;GAC5D,IAAI,gBAAgB,MACnB,MAAM,KAAK,YAAY;EAEzB;EAEA,OAAO;GACC;GACP,SAAS,SAAS,IAAI,KAAK,KAAK,YAAY;GAC5C,MAAM,SAAS,IAAI,KAAK,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;EACrE;CACD;CAEA,MAAM,SAAS,KAAuC;EACrD,MAAM,KAAK,QAAQ,YAAY,yBAAyB;GACvD,QAAQ;GACR,MAAM,KAAK,UAAU,EAAE,iBAAiB,IAAI,CAAC;EAC9C,CAAC;CACF;CAEA,MAAM,WAAW,KAAuC;EACvD,MAAM,KAAK,QAAQ,cAAc,2BAA2B;GAC3D,QAAQ;GACR,MAAM,KAAK,UAAU,EAAE,iBAAiB,IAAI,CAAC;EAC9C,CAAC;CACF;CAEA,MAAM,OAAO,KAAuC;EACnD,MAAM,KAAK,QAAQ,UAAU,oBAAoB;GAChD,QAAQ;GACR,MAAM,KAAK,UAAU,EAAE,iBAAiB,IAAI,CAAC;EAC9C,CAAC;CACF;CAEA,MAAM,cAA6C;EAClD,MAAM,OAAO,MAAM,KAAK,QAAQ,eAAe,kCAAkC,EAAE,QAAQ,MAAM,CAAC;EAClG,MAAM,WAAW,SAAS,IAAI,IAAI,OAAO,CAAC;EAE1C,OAAO;GACN,kBAAkB,SAAS,qBAAqB;GAChD,aAAa,SAAS,gBAAgB;GACtC,iBAAiB,SAAS,oBAAoB;EAC/C;CACD;CAEA,MAAM,eAAe,UAA+C;EACnE,MAAM,KAAK,QAAQ,kBAAkB,kCAAkC;GACtE,QAAQ;GACR,MAAM,KAAK,UAAU;IACpB,kBAAkB,SAAS;IAC3B,aAAa,SAAS;IACtB,iBAAiB,SAAS;GAC3B,CAAgC;EACjC,CAAC;CACF;;CAGA,MAAc,QACb,WACA,MACA,MACA,OACmB;EACnB,MAAM,MAAM,MAAM,KAAK,QAAQ,WAC9B,MACA;GACC,GAAG;GACH,SAAS,EAAE,gBAAgB,mBAAmB;EAC/C,GACA,KACD;EACA,IAAI,CAAC,IAAI,IAAI,MAAM,IAAI,sBAAsB,IAAI,QAAQ,WAAW,IAAI,UAAU;EAElF,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,CAAC,MAAM,OAAO,KAAA;EAElB,IAAI;EACJ,IAAI;GACH,OAAO,KAAK,MAAM,IAAI;EACvB,SAAS,IAAI;GACZ,MAAM,IAAI,sBAAsB,IAAI,QAAQ,WAAW,yBAAyB,EAAE,OAAO,GAAG,CAAC;EAC9F;EACA,OAAO,SAAS,IAAI,IAAK,KAAK,QAAQ,OAAQ;CAC/C;AACD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region ../plus/notifications/src/context.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Optional diagnostics sink. The package never logs on its own; the host routes these to its logger.
|
|
4
|
+
*/
|
|
5
|
+
export interface NotificationsLogger {
|
|
6
|
+
debug?(message: string): void;
|
|
7
|
+
warn?(message: string): void;
|
|
8
|
+
error?(ex: unknown, message?: string): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Everything the notifications package needs from its host. The package cannot import `vscode` or reach
|
|
12
|
+
* into the extension host, so the only way it talks to the outside world is through this context.
|
|
13
|
+
*/
|
|
14
|
+
export interface NotificationsContext {
|
|
15
|
+
/** The `productType` the notifications service filters by, e.g. `gitlens`. The package never hardcodes one. */
|
|
16
|
+
readonly productType: string;
|
|
17
|
+
/**
|
|
18
|
+
* Authenticated request against the GK cloud API. `path` is relative to the API root, has no leading slash
|
|
19
|
+
* and never carries a query string, e.g. `v1/notifications`; any query comes separately in `query`. A non-2xx
|
|
20
|
+
* response is returned, not thrown.
|
|
21
|
+
*/
|
|
22
|
+
fetchGkApi(path: string, init?: RequestInit, query?: URLSearchParams): Promise<Response>;
|
|
23
|
+
/** Current time in ms since the epoch; a test seam that defaults to `Date.now()`. */
|
|
24
|
+
now?(): number;
|
|
25
|
+
readonly log?: NotificationsLogger;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//# sourceMappingURL=context.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region ../plus/notifications/src/errors.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A failed request to the notifications service: a non-2xx response, or a 2xx one whose body isn't valid JSON
|
|
4
|
+
* (e.g. an HTML error page from a proxy). The message is for logs, not for display.
|
|
5
|
+
*/
|
|
6
|
+
export declare class NotificationsApiError extends Error {
|
|
7
|
+
readonly status: number;
|
|
8
|
+
readonly operation: string;
|
|
9
|
+
static is(ex: unknown): ex is NotificationsApiError;
|
|
10
|
+
constructor(status: number, operation: string, reason?: string, options?: ErrorOptions);
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region ../plus/notifications/src/errors.ts
|
|
2
|
+
/**
|
|
3
|
+
* A failed request to the notifications service: a non-2xx response, or a 2xx one whose body isn't valid JSON
|
|
4
|
+
* (e.g. an HTML error page from a proxy). The message is for logs, not for display.
|
|
5
|
+
*/
|
|
6
|
+
var NotificationsApiError = class NotificationsApiError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
operation;
|
|
9
|
+
static is(ex) {
|
|
10
|
+
return ex instanceof NotificationsApiError;
|
|
11
|
+
}
|
|
12
|
+
constructor(status, operation, reason, options) {
|
|
13
|
+
super(`Notifications request '${operation}' failed: ${status}${reason ? ` ${reason}` : ""}`, options);
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.operation = operation;
|
|
16
|
+
this.name = "NotificationsApiError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
export { NotificationsApiError };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../../../plus/notifications/src/errors.ts"],"sourcesContent":["/**\n * A failed request to the notifications service: a non-2xx response, or a 2xx one whose body isn't valid JSON\n * (e.g. an HTML error page from a proxy). The message is for logs, not for display.\n */\nexport class NotificationsApiError extends Error {\n\tstatic is(ex: unknown): ex is NotificationsApiError {\n\t\treturn ex instanceof NotificationsApiError;\n\t}\n\n\tconstructor(\n\t\treadonly status: number,\n\t\treadonly operation: string,\n\t\treason?: string,\n\t\toptions?: ErrorOptions,\n\t) {\n\t\tsuper(`Notifications request '${operation}' failed: ${status}${reason ? ` ${reason}` : ''}`, options);\n\t\tthis.name = 'NotificationsApiError';\n\t}\n}\n"],"mappings":";;;;;AAIA,IAAa,wBAAb,MAAa,8BAA8B,MAAM;CAMtC;CACA;CANV,OAAO,GAAG,IAA0C;EACnD,OAAO,cAAc;CACtB;CAEA,YACC,QACA,WACA,QACA,SACC;EACD,MAAM,0BAA0B,UAAU,YAAY,SAAS,SAAS,IAAI,WAAW,MAAM,OAAO;EAL3F,KAAA,SAAA;EACA,KAAA,YAAA;EAKT,KAAK,OAAO;CACb;AACD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
//#region ../plus/notifications/src/models.d.ts
|
|
2
|
+
export type NotificationContentType = 'feature' | 'help' | 'marketing' | 'system' | 'security';
|
|
3
|
+
/** The events this package knows how to render; anything else is `unknown` and shown via its `fallback`. */
|
|
4
|
+
export type NotificationEvent = 'general' | 'callToAction' | 'projectShared' | 'nudge' | 'unknown';
|
|
5
|
+
/** A notification as `notifications-service-v2` returns it from `GET v1/notifications`. Untrusted input. */
|
|
6
|
+
export interface RawNotification {
|
|
7
|
+
notificationId: string;
|
|
8
|
+
name: string;
|
|
9
|
+
title?: string | null;
|
|
10
|
+
notificationType: 'system' | 'user';
|
|
11
|
+
contentType: NotificationContentType;
|
|
12
|
+
/** Any string; the known values are those of {@link NotificationEvent} other than `unknown`. */
|
|
13
|
+
event: string;
|
|
14
|
+
/** ISO 8601 timestamps. */
|
|
15
|
+
readAt?: string | null;
|
|
16
|
+
expiresAt?: string | null;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
fallback?: string | null;
|
|
20
|
+
payload?: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface NotificationSettings {
|
|
23
|
+
marketingEnabled: boolean;
|
|
24
|
+
helpEnabled: boolean;
|
|
25
|
+
securityEnabled: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The parts of a `projectShared` notification. The package cannot localize, so the host assembles the sentence
|
|
29
|
+
* ("In {organization}, {owner} created a new Team Workspace: {project}", plus the teams when there are any).
|
|
30
|
+
*/
|
|
31
|
+
export interface ProjectSharedDetails {
|
|
32
|
+
organization: string;
|
|
33
|
+
owner: string;
|
|
34
|
+
project: string;
|
|
35
|
+
teams: string[];
|
|
36
|
+
}
|
|
37
|
+
/** A validated notification. Plain data, so it can be persisted and sent over RPC as is. */
|
|
38
|
+
export interface GkNotification {
|
|
39
|
+
id: string;
|
|
40
|
+
event: NotificationEvent;
|
|
41
|
+
contentType: NotificationContentType;
|
|
42
|
+
/**
|
|
43
|
+
* The server's display `title`; `undefined` when unset, in which case the host supplies its own header.
|
|
44
|
+
* Never the server's internal `name`.
|
|
45
|
+
*/
|
|
46
|
+
headline?: string;
|
|
47
|
+
/**
|
|
48
|
+
* A plain-text one-line summary of the notice (the server's `payload.desktopMessage`, else `fallback`), when set;
|
|
49
|
+
* the host uses it where there's no {@link headline}. Never markdown-rendered.
|
|
50
|
+
*/
|
|
51
|
+
summary?: string;
|
|
52
|
+
/** Markdown. `undefined` for `projectShared`, whose body the host builds from {@link projectShared}. */
|
|
53
|
+
body: string | undefined;
|
|
54
|
+
/** Only for `callToAction`; the URL is always `https:`. */
|
|
55
|
+
cta?: {
|
|
56
|
+
text: string;
|
|
57
|
+
url: string;
|
|
58
|
+
};
|
|
59
|
+
/** Only for `projectShared`. */
|
|
60
|
+
projectShared?: ProjectSharedDetails;
|
|
61
|
+
/** Timestamps in ms since the epoch. */
|
|
62
|
+
createdAt: number;
|
|
63
|
+
readAt?: number;
|
|
64
|
+
expiresAt?: number;
|
|
65
|
+
/** Set when an unknown event is shown through its `fallback` text. */
|
|
66
|
+
needsNewerVersion?: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface NotificationsPage {
|
|
69
|
+
items: GkNotification[];
|
|
70
|
+
hasMore: boolean;
|
|
71
|
+
page: number;
|
|
72
|
+
}
|
|
73
|
+
export type NotificationsStatus = 'idle' | 'loading' | 'ready' | 'error';
|
|
74
|
+
export interface NotificationsState {
|
|
75
|
+
/** Newest first. */
|
|
76
|
+
readonly items: readonly GkNotification[];
|
|
77
|
+
readonly hasMore: boolean;
|
|
78
|
+
readonly status: NotificationsStatus;
|
|
79
|
+
readonly lastSyncedAt: number | undefined;
|
|
80
|
+
readonly settings: NotificationSettings | undefined;
|
|
81
|
+
/** Unread among the loaded items. */
|
|
82
|
+
readonly unreadCount: number;
|
|
83
|
+
}
|
|
84
|
+
/** What the host persists between sessions; see `NotificationsService.toSnapshot()` and `restore()`. */
|
|
85
|
+
export interface NotificationsSnapshot {
|
|
86
|
+
items: GkNotification[];
|
|
87
|
+
hasMore: boolean;
|
|
88
|
+
/** The last page loaded, 1-based. */
|
|
89
|
+
page: number;
|
|
90
|
+
lastSyncedAt: number | undefined;
|
|
91
|
+
settings: NotificationSettings | undefined;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//# sourceMappingURL=models.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { UnifiedDisposable } from "../../utils/disposable.js";
|
|
2
|
+
import { Event } from "../../utils/event.js";
|
|
3
|
+
import { NotificationsContext } from "./context.js";
|
|
4
|
+
import { GkNotification, NotificationSettings, NotificationsSnapshot, NotificationsState } from "./models.js";
|
|
5
|
+
//#region ../plus/notifications/src/notificationsService.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* How far before the newest previously-held notification's `createdAt` a notification may fall and still count as
|
|
8
|
+
* newly arrived in {@link NotificationsService.refresh}'s result. Both sides are server timestamps; the margin only
|
|
9
|
+
* covers concurrent inserts committing out of `created_at` order on the server.
|
|
10
|
+
*/
|
|
11
|
+
export declare const newToastableSkewMargin: number;
|
|
12
|
+
/**
|
|
13
|
+
* Holds the user's notifications for one product and keeps them in sync with `notifications-service-v2`.
|
|
14
|
+
* Read/unread/delete and settings changes apply optimistically and roll back if the request fails (a 404 on
|
|
15
|
+
* read/unread/delete means the notifications are already gone, so it isn't a failure). The service never polls on
|
|
16
|
+
* its own: the host decides when to {@link refresh}, and each refresh reports which notices newly arrived and
|
|
17
|
+
* should toast; how (and whether) to show them stays the host's call.
|
|
18
|
+
*/
|
|
19
|
+
export declare class NotificationsService implements UnifiedDisposable {
|
|
20
|
+
private readonly context;
|
|
21
|
+
private readonly _onDidChange;
|
|
22
|
+
get onDidChange(): Event<void>;
|
|
23
|
+
private readonly api;
|
|
24
|
+
private _items;
|
|
25
|
+
private _hasMore;
|
|
26
|
+
/** The last page loaded, 1-based; 0 before the first load. */
|
|
27
|
+
private _page;
|
|
28
|
+
private _status;
|
|
29
|
+
private _lastSyncedAt;
|
|
30
|
+
private _settings;
|
|
31
|
+
/** The settings the server last acknowledged (fetched, or successfully saved) */
|
|
32
|
+
private _confirmedSettings;
|
|
33
|
+
private _settingsPost;
|
|
34
|
+
private _settingsFollowUp;
|
|
35
|
+
private _refreshing;
|
|
36
|
+
private _loadingMore;
|
|
37
|
+
/**
|
|
38
|
+
* Actions in flight (or settled while a refresh that started before them was still fetching), by id. A refresh
|
|
39
|
+
* re-applies them so data fetched before the server saw an action doesn't undo it.
|
|
40
|
+
*/
|
|
41
|
+
private readonly _overrides;
|
|
42
|
+
/** For items a refresh re-applied an override to: the override's output → which override and the server's item */
|
|
43
|
+
private readonly _overridden;
|
|
44
|
+
constructor(context: NotificationsContext);
|
|
45
|
+
dispose(): void;
|
|
46
|
+
[Symbol.dispose](): void;
|
|
47
|
+
get unreadCount(): number;
|
|
48
|
+
getState(): NotificationsState;
|
|
49
|
+
/**
|
|
50
|
+
* Re-fetches every page already loaded (up to {@link maxRefreshPages}), so read state, deletions and expiry
|
|
51
|
+
* from elsewhere reach them without collapsing a list the user paged through. Expired items are pruned and
|
|
52
|
+
* local actions still in flight are kept. Never throws: on failure the cached items stay and the status
|
|
53
|
+
* becomes `error`.
|
|
54
|
+
*
|
|
55
|
+
* Resolves to the notices to toast: the unread, toast-eligible ones that newly arrived with this refresh,
|
|
56
|
+
* newest first. Empty when the refresh failed, when nothing had synced before it (no backfill: the first load
|
|
57
|
+
* for an account is the existing inbox, not news; a restored snapshot with a `lastSyncedAt` does count as
|
|
58
|
+
* synced, so what arrived while the host was closed still toasts), or when nothing is new. New means its id
|
|
59
|
+
* wasn't held before the refresh AND it was created after the newest of those held, less
|
|
60
|
+
* {@link newToastableSkewMargin}. Only server timestamps are compared, so the client's clock can't hide a
|
|
61
|
+
* notice. The id check keeps a notice already seen from toasting again; the time check keeps an old one that
|
|
62
|
+
* only now shifts into the first page (after a deletion, or a page boundary moving) from toasting as if it
|
|
63
|
+
* were new. With nothing held before there is no cutoff.
|
|
64
|
+
*
|
|
65
|
+
* Concurrent calls share one request and resolve to the same list, so the result is for ONE caller to act on
|
|
66
|
+
* once (the host's refresh loop); other callers should ignore it.
|
|
67
|
+
*/
|
|
68
|
+
refresh(): Promise<GkNotification[]>;
|
|
69
|
+
private refreshCore;
|
|
70
|
+
/**
|
|
71
|
+
* Loads the next page, after any refresh in flight (which may change which page is next). Throws on failure,
|
|
72
|
+
* leaving the loaded items as they were. Concurrent calls share one request.
|
|
73
|
+
*/
|
|
74
|
+
loadMore(): Promise<void>;
|
|
75
|
+
private loadMoreCore;
|
|
76
|
+
markRead(ids: readonly string[]): Promise<void>;
|
|
77
|
+
markUnread(ids: readonly string[]): Promise<void>;
|
|
78
|
+
delete(ids: readonly string[]): Promise<void>;
|
|
79
|
+
/** Marks every loaded unread notification read. */
|
|
80
|
+
markAllRead(): Promise<void>;
|
|
81
|
+
/** Deletes every loaded read notification. */
|
|
82
|
+
deleteAllRead(): Promise<void>;
|
|
83
|
+
/** Fetches the user's notification settings (and caches them in the state). */
|
|
84
|
+
getSettings(): Promise<NotificationSettings>;
|
|
85
|
+
/**
|
|
86
|
+
* Applies `changes` optimistically, then saves. The server stores the whole settings object from each request,
|
|
87
|
+
* so POSTs must not overlap (they could land out of order and leave the older state): at most one is in flight,
|
|
88
|
+
* and calls made meanwhile share ONE follow-up POST that sends the latest state. Each call settles with the
|
|
89
|
+
* outcome of the POST that carried its change.
|
|
90
|
+
*/
|
|
91
|
+
updateSettings(changes: Partial<NotificationSettings>): Promise<NotificationSettings>;
|
|
92
|
+
private trackSettingsPost;
|
|
93
|
+
/** Sends the latest optimistic settings; the confirmed state is what was sent, not the server's echo. */
|
|
94
|
+
private postSettings;
|
|
95
|
+
/** The held notices that are new relative to `previous`, newest first; see {@link refresh} for the rules */
|
|
96
|
+
private newToastableSince;
|
|
97
|
+
toSnapshot(): NotificationsSnapshot;
|
|
98
|
+
/** Seeds the state from a snapshot the host persisted; expired items are pruned. */
|
|
99
|
+
restore(snapshot: NotificationsSnapshot): void;
|
|
100
|
+
/** On a 404 (the notifications are already gone) the targets are removed instead of rolled back. */
|
|
101
|
+
private updateOptimistically;
|
|
102
|
+
/**
|
|
103
|
+
* Records `override` for `ids` until the action settles; on success, until any refresh or Load More in flight
|
|
104
|
+
* (either may have fetched before the server applied the action) has landed too. Returns the release for when
|
|
105
|
+
* it settles.
|
|
106
|
+
*/
|
|
107
|
+
private trackOverrides;
|
|
108
|
+
private applyOverrides;
|
|
109
|
+
private pruneExpired;
|
|
110
|
+
private setStatus;
|
|
111
|
+
private fireChange;
|
|
112
|
+
private now;
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//# sourceMappingURL=notificationsService.d.ts.map
|