deepline 0.3.14 → 0.3.16
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/bundling-sources/sdk/src/client.ts +25 -13
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +1 -1
- package/dist/bundling-sources/shared_libs/product-notifications/contract.ts +76 -0
- package/dist/cli/index.js +106 -30
- package/dist/cli/index.mjs +106 -30
- package/dist/index.d.mts +25 -15
- package/dist/index.d.ts +25 -15
- package/dist/index.js +9 -5
- package/dist/index.mjs +9 -5
- package/package.json +1 -1
|
@@ -98,6 +98,7 @@ import {
|
|
|
98
98
|
TOOL_EXECUTION_ERROR_SCHEMA_HEADER,
|
|
99
99
|
TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
|
|
100
100
|
} from '../../shared_libs/tool-execution-error.js';
|
|
101
|
+
|
|
101
102
|
import { decodePlayRunPublicStatus } from '../../shared_libs/play-runtime/run-lifecycle-policy.js';
|
|
102
103
|
import {
|
|
103
104
|
legacyRawFromToolResponseRawV2,
|
|
@@ -105,6 +106,20 @@ import {
|
|
|
105
106
|
RAW_V2_TOOL_RESPONSE_CONTRACT,
|
|
106
107
|
} from '../../shared_libs/play-runtime/tool-response-contract.js';
|
|
107
108
|
|
|
109
|
+
export type SlackNotificationTarget =
|
|
110
|
+
| { channel: string; memberId?: never }
|
|
111
|
+
| { channel?: never; memberId: string };
|
|
112
|
+
|
|
113
|
+
export type CreateNotificationInput = {
|
|
114
|
+
name: string;
|
|
115
|
+
provider: 'slack';
|
|
116
|
+
eventTypes: string[];
|
|
117
|
+
} & SlackNotificationTarget;
|
|
118
|
+
|
|
119
|
+
export type UpdateNotificationInput =
|
|
120
|
+
| { enabled: boolean }
|
|
121
|
+
| ({ name: string; eventTypes: string[] } & SlackNotificationTarget);
|
|
122
|
+
|
|
108
123
|
const TERMINAL_PLAY_STATUSES = new Set(['completed', 'failed', 'cancelled']);
|
|
109
124
|
const INCLUDE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
|
|
110
125
|
const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
|
|
@@ -2835,7 +2850,8 @@ export class DeeplineClient {
|
|
|
2835
2850
|
}
|
|
2836
2851
|
|
|
2837
2852
|
type DirectStageResult =
|
|
2838
|
-
{ ref: PlayStagedFileRef }
|
|
2853
|
+
| { ref: PlayStagedFileRef }
|
|
2854
|
+
| { fallbackFile: (typeof files)[number] };
|
|
2839
2855
|
const directResults: DirectStageResult[] = await Promise.all(
|
|
2840
2856
|
files.map(async (file) => {
|
|
2841
2857
|
const upload = uploadByIdentity.get(
|
|
@@ -3930,9 +3946,12 @@ export class DeeplineClient {
|
|
|
3930
3946
|
return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
|
|
3931
3947
|
}
|
|
3932
3948
|
|
|
3933
|
-
/** Select
|
|
3934
|
-
async setNotificationSlack(
|
|
3935
|
-
return this.http.put(
|
|
3949
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
3950
|
+
async setNotificationSlack(destination: string | { memberId: string }) {
|
|
3951
|
+
return this.http.put(
|
|
3952
|
+
'/api/v2/settings/notifications',
|
|
3953
|
+
typeof destination === 'string' ? { channel: destination } : destination,
|
|
3954
|
+
);
|
|
3936
3955
|
}
|
|
3937
3956
|
|
|
3938
3957
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
@@ -3998,21 +4017,14 @@ export class DeeplineClient {
|
|
|
3998
4017
|
}
|
|
3999
4018
|
|
|
4000
4019
|
/** Create a named notification routed through an existing provider integration. */
|
|
4001
|
-
async createNotification(input: {
|
|
4002
|
-
name: string;
|
|
4003
|
-
provider: 'slack';
|
|
4004
|
-
channel: string;
|
|
4005
|
-
eventTypes: string[];
|
|
4006
|
-
}) {
|
|
4020
|
+
async createNotification(input: CreateNotificationInput) {
|
|
4007
4021
|
return this.http.post('/api/v2/notifications', input);
|
|
4008
4022
|
}
|
|
4009
4023
|
|
|
4010
4024
|
/** Update a notification's target, event selection, or enabled state. */
|
|
4011
4025
|
async updateNotification(
|
|
4012
4026
|
notificationId: string,
|
|
4013
|
-
input:
|
|
4014
|
-
| { enabled: boolean }
|
|
4015
|
-
| { name: string; channel: string; eventTypes: string[] },
|
|
4027
|
+
input: UpdateNotificationInput,
|
|
4016
4028
|
) {
|
|
4017
4029
|
return this.http.patch(
|
|
4018
4030
|
`/api/v2/notifications/${encodeURIComponent(notificationId)}`,
|
|
@@ -192,7 +192,7 @@ export const SDK_RELEASE = {
|
|
|
192
192
|
// 0.3.0 introduces raw-v2: complete scrubbed provider responses are
|
|
193
193
|
// available at toolResponse.rawV2 while toolResponse.raw and all declared
|
|
194
194
|
// getters keep their established compatibility behavior.
|
|
195
|
-
version: '0.3.
|
|
195
|
+
version: '0.3.16',
|
|
196
196
|
updateSummary:
|
|
197
197
|
'New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.',
|
|
198
198
|
contracts: {
|
|
@@ -1136,7 +1136,7 @@ export interface ProductNotification {
|
|
|
1136
1136
|
id: string;
|
|
1137
1137
|
name: string;
|
|
1138
1138
|
provider: string;
|
|
1139
|
-
target: { id: string; name: string };
|
|
1139
|
+
target: { id: string; name: string; kind?: 'channel' | 'member' };
|
|
1140
1140
|
enabled: boolean;
|
|
1141
1141
|
status: string;
|
|
1142
1142
|
eventTypes: string[];
|
|
@@ -75,14 +75,90 @@ export function defaultProductNotificationEventTypes(): ProductNotificationEvent
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export const PRODUCT_NOTIFICATION_DESTINATION_KINDS = ['slack'] as const;
|
|
78
|
+
/**
|
|
79
|
+
* The legacy settings API predates named notification rules. Its shortcuts
|
|
80
|
+
* operate on this deterministic compatibility rule when more than one Slack
|
|
81
|
+
* notification exists.
|
|
82
|
+
*/
|
|
83
|
+
export const LEGACY_SLACK_NOTIFICATION_NAME = 'Slack notifications';
|
|
84
|
+
export const PRODUCT_NOTIFICATION_LEGACY_SELECTION_ERROR_CODE =
|
|
85
|
+
'PRODUCT_NOTIFICATION_LEGACY_SELECTION_AMBIGUOUS';
|
|
86
|
+
|
|
87
|
+
export type LegacySlackNotificationDestination = {
|
|
88
|
+
kind: string;
|
|
89
|
+
name: string;
|
|
90
|
+
archivedAt?: number;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export class ProductNotificationLegacySelectionError extends Error {
|
|
94
|
+
constructor(message: string) {
|
|
95
|
+
super(message);
|
|
96
|
+
this.name = 'ProductNotificationLegacySelectionError';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function isProductNotificationLegacySelectionError(
|
|
101
|
+
error: unknown,
|
|
102
|
+
): boolean {
|
|
103
|
+
if (!error || typeof error !== 'object' || !('data' in error)) return false;
|
|
104
|
+
const data = (error as { data?: unknown }).data;
|
|
105
|
+
return (
|
|
106
|
+
typeof data === 'object' &&
|
|
107
|
+
data !== null &&
|
|
108
|
+
(data as { code?: unknown }).code ===
|
|
109
|
+
PRODUCT_NOTIFICATION_LEGACY_SELECTION_ERROR_CODE
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Resolve the singleton target for the legacy settings API without ever
|
|
115
|
+
* silently choosing one of several named notification rules.
|
|
116
|
+
*/
|
|
117
|
+
export function resolveLegacySlackNotification<
|
|
118
|
+
T extends LegacySlackNotificationDestination,
|
|
119
|
+
>(destinations: readonly T[]): T | null {
|
|
120
|
+
const slackDestinations = destinations.filter(
|
|
121
|
+
(destination) =>
|
|
122
|
+
destination.kind === 'slack' && destination.archivedAt === undefined,
|
|
123
|
+
);
|
|
124
|
+
const canonical = slackDestinations.filter(
|
|
125
|
+
(destination) => destination.name === LEGACY_SLACK_NOTIFICATION_NAME,
|
|
126
|
+
);
|
|
127
|
+
if (canonical.length === 1) return canonical[0]!;
|
|
128
|
+
if (canonical.length > 1) {
|
|
129
|
+
throw new ProductNotificationLegacySelectionError(
|
|
130
|
+
`More than one \"${LEGACY_SLACK_NOTIFICATION_NAME}\" Slack notification exists. Use the named notification API to choose one.`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (slackDestinations.length <= 1) return slackDestinations[0] ?? null;
|
|
134
|
+
throw new ProductNotificationLegacySelectionError(
|
|
135
|
+
'More than one Slack notification is configured. Use the named notification API to choose one.',
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
78
139
|
export const PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
|
|
79
140
|
'channels:read',
|
|
80
141
|
'chat:write',
|
|
81
142
|
'groups:read',
|
|
143
|
+
'im:write',
|
|
82
144
|
] as const;
|
|
83
145
|
export type ProductNotificationDestinationKind =
|
|
84
146
|
(typeof PRODUCT_NOTIFICATION_DESTINATION_KINDS)[number];
|
|
85
147
|
|
|
148
|
+
export const PRODUCT_NOTIFICATION_SLACK_TARGET_KINDS = [
|
|
149
|
+
'channel',
|
|
150
|
+
'member',
|
|
151
|
+
] as const;
|
|
152
|
+
export type ProductNotificationSlackTargetKind =
|
|
153
|
+
(typeof PRODUCT_NOTIFICATION_SLACK_TARGET_KINDS)[number];
|
|
154
|
+
|
|
155
|
+
/** Slack member IDs begin with U (or W for Enterprise Grid workspaces). */
|
|
156
|
+
export function isProductNotificationSlackMemberId(
|
|
157
|
+
value: unknown,
|
|
158
|
+
): value is string {
|
|
159
|
+
return typeof value === 'string' && /^[UW][A-Z0-9]{8,}$/.test(value.trim());
|
|
160
|
+
}
|
|
161
|
+
|
|
86
162
|
export const PRODUCT_NOTIFICATION_DELIVERY_STATES = [
|
|
87
163
|
'pending',
|
|
88
164
|
'delivering',
|
package/dist/cli/index.js
CHANGED
|
@@ -1047,7 +1047,7 @@ var SDK_RELEASE = {
|
|
|
1047
1047
|
// 0.3.0 introduces raw-v2: complete scrubbed provider responses are
|
|
1048
1048
|
// available at toolResponse.rawV2 while toolResponse.raw and all declared
|
|
1049
1049
|
// getters keep their established compatibility behavior.
|
|
1050
|
-
version: "0.3.
|
|
1050
|
+
version: "0.3.16",
|
|
1051
1051
|
updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
|
|
1052
1052
|
contracts: {
|
|
1053
1053
|
api: {
|
|
@@ -1904,10 +1904,36 @@ var PRODUCT_NOTIFICATION_EVENT_CATALOG = [
|
|
|
1904
1904
|
var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
|
|
1905
1905
|
PRODUCT_NOTIFICATION_EVENT_CATALOG.map((event) => event.id)
|
|
1906
1906
|
);
|
|
1907
|
+
var LEGACY_SLACK_NOTIFICATION_NAME = "Slack notifications";
|
|
1908
|
+
var ProductNotificationLegacySelectionError = class extends Error {
|
|
1909
|
+
constructor(message) {
|
|
1910
|
+
super(message);
|
|
1911
|
+
this.name = "ProductNotificationLegacySelectionError";
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
function resolveLegacySlackNotification(destinations) {
|
|
1915
|
+
const slackDestinations = destinations.filter(
|
|
1916
|
+
(destination) => destination.kind === "slack" && destination.archivedAt === void 0
|
|
1917
|
+
);
|
|
1918
|
+
const canonical = slackDestinations.filter(
|
|
1919
|
+
(destination) => destination.name === LEGACY_SLACK_NOTIFICATION_NAME
|
|
1920
|
+
);
|
|
1921
|
+
if (canonical.length === 1) return canonical[0];
|
|
1922
|
+
if (canonical.length > 1) {
|
|
1923
|
+
throw new ProductNotificationLegacySelectionError(
|
|
1924
|
+
`More than one "${LEGACY_SLACK_NOTIFICATION_NAME}" Slack notification exists. Use the named notification API to choose one.`
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
if (slackDestinations.length <= 1) return slackDestinations[0] ?? null;
|
|
1928
|
+
throw new ProductNotificationLegacySelectionError(
|
|
1929
|
+
"More than one Slack notification is configured. Use the named notification API to choose one."
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1907
1932
|
var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
|
|
1908
1933
|
"channels:read",
|
|
1909
1934
|
"chat:write",
|
|
1910
|
-
"groups:read"
|
|
1935
|
+
"groups:read",
|
|
1936
|
+
"im:write"
|
|
1911
1937
|
];
|
|
1912
1938
|
var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
|
|
1913
1939
|
0,
|
|
@@ -5987,9 +6013,12 @@ var DeeplineClient = class {
|
|
|
5987
6013
|
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
5988
6014
|
return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
|
|
5989
6015
|
}
|
|
5990
|
-
/** Select
|
|
5991
|
-
async setNotificationSlack(
|
|
5992
|
-
return this.http.put(
|
|
6016
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
6017
|
+
async setNotificationSlack(destination) {
|
|
6018
|
+
return this.http.put(
|
|
6019
|
+
"/api/v2/settings/notifications",
|
|
6020
|
+
typeof destination === "string" ? { channel: destination } : destination
|
|
6021
|
+
);
|
|
5993
6022
|
}
|
|
5994
6023
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
5995
6024
|
async testNotificationSlack() {
|
|
@@ -36089,11 +36118,23 @@ var eventHelp = PRODUCT_NOTIFICATION_EVENT_CATALOG.map(
|
|
|
36089
36118
|
(event) => ` ${event.id.padEnd(28)} ${event.description}`
|
|
36090
36119
|
).join("\n");
|
|
36091
36120
|
function slackDestination(settings) {
|
|
36092
|
-
|
|
36121
|
+
const destinations = settings.destinations.map(
|
|
36122
|
+
(entry) => ({
|
|
36123
|
+
...entry,
|
|
36124
|
+
kind: typeof entry.kind === "string" ? entry.kind : "",
|
|
36125
|
+
name: typeof entry.name === "string" ? entry.name : "",
|
|
36126
|
+
archivedAt: typeof entry.archivedAt === "number" ? entry.archivedAt : void 0
|
|
36127
|
+
})
|
|
36128
|
+
);
|
|
36129
|
+
return resolveLegacySlackNotification(
|
|
36130
|
+
destinations
|
|
36131
|
+
);
|
|
36093
36132
|
}
|
|
36094
|
-
function eventLines(settings) {
|
|
36133
|
+
function eventLines(settings, destinationId) {
|
|
36095
36134
|
const enabled = new Map(
|
|
36096
|
-
settings.subscriptions.
|
|
36135
|
+
settings.subscriptions.filter(
|
|
36136
|
+
(entry) => !destinationId || entry.destinationId === destinationId
|
|
36137
|
+
).map((entry) => [entry.eventType, entry.enabled])
|
|
36097
36138
|
);
|
|
36098
36139
|
return settings.catalog.map(
|
|
36099
36140
|
(event) => `${event.id}: ${enabled.get(event.id) === true ? "enabled" : "disabled"} \u2014 ${event.description}`
|
|
@@ -36111,6 +36152,7 @@ function requireCatalogEvent(settings, eventType) {
|
|
|
36111
36152
|
async function printSettings(options) {
|
|
36112
36153
|
const settings = await new DeeplineClient().getNotificationSettings();
|
|
36113
36154
|
const slack = slackDestination(settings);
|
|
36155
|
+
const destinationId = typeof slack?._id === "string" ? slack._id : void 0;
|
|
36114
36156
|
printCommandEnvelope(
|
|
36115
36157
|
{
|
|
36116
36158
|
settings,
|
|
@@ -36120,11 +36162,14 @@ async function printSettings(options) {
|
|
|
36120
36162
|
title: "Slack destination",
|
|
36121
36163
|
lines: slack ? [
|
|
36122
36164
|
`status: ${String(slack.status ?? "unknown")}`,
|
|
36123
|
-
|
|
36165
|
+
`${slack.targetKind === "member" ? "member" : "channel"}: ${slack.targetKind === "member" ? "@" : "#"}${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
|
|
36124
36166
|
...slack.lastErrorMessage ? [`issue: ${String(slack.lastErrorMessage)}`] : []
|
|
36125
36167
|
] : ["Not configured."]
|
|
36126
36168
|
},
|
|
36127
|
-
{
|
|
36169
|
+
{
|
|
36170
|
+
title: "subscriptions",
|
|
36171
|
+
lines: eventLines(settings, destinationId)
|
|
36172
|
+
},
|
|
36128
36173
|
{
|
|
36129
36174
|
title: "dead letter queue",
|
|
36130
36175
|
lines: [
|
|
@@ -36224,27 +36269,32 @@ notifications; there is no general integrations CLI.
|
|
|
36224
36269
|
{ json: options.json }
|
|
36225
36270
|
);
|
|
36226
36271
|
});
|
|
36227
|
-
notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").
|
|
36272
|
+
notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").option("--channel <channel>", "Slack channel name or ID").option("--member-id <id>", "Slack member ID, for example U0123456789").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(
|
|
36228
36273
|
async (destination, options) => {
|
|
36229
36274
|
if (destination !== "slack")
|
|
36230
36275
|
throw new Error("Only slack is supported.");
|
|
36276
|
+
if (Boolean(options.channel) === Boolean(options.memberId)) {
|
|
36277
|
+
throw new Error("Provide exactly one of --channel or --member-id.");
|
|
36278
|
+
}
|
|
36279
|
+
const target = options.memberId ? { memberId: options.memberId } : options.channel;
|
|
36231
36280
|
if (options.dryRun) {
|
|
36232
36281
|
printCommandEnvelope(
|
|
36233
|
-
{ dryRun: true, destination,
|
|
36282
|
+
{ dryRun: true, destination, target },
|
|
36234
36283
|
{ json: options.json }
|
|
36235
36284
|
);
|
|
36236
36285
|
return;
|
|
36237
36286
|
}
|
|
36238
|
-
const result = await new DeeplineClient().setNotificationSlack(
|
|
36239
|
-
options.channel
|
|
36240
|
-
);
|
|
36287
|
+
const result = await new DeeplineClient().setNotificationSlack(target);
|
|
36241
36288
|
printCommandEnvelope(
|
|
36242
36289
|
{
|
|
36243
36290
|
ok: true,
|
|
36244
36291
|
result,
|
|
36245
36292
|
render: {
|
|
36246
36293
|
sections: [
|
|
36247
|
-
{
|
|
36294
|
+
{
|
|
36295
|
+
title: "Slack destination saved",
|
|
36296
|
+
lines: [options.memberId ?? options.channel]
|
|
36297
|
+
}
|
|
36248
36298
|
],
|
|
36249
36299
|
actions: [
|
|
36250
36300
|
{
|
|
@@ -36308,12 +36358,19 @@ ${eventHelp}
|
|
|
36308
36358
|
);
|
|
36309
36359
|
subscriptions.command("list").description("List every supported event and its current state.").option("--json", "Emit JSON output").action(async (options) => {
|
|
36310
36360
|
const current = await new DeeplineClient().getNotificationSettings();
|
|
36361
|
+
const destination = slackDestination(current);
|
|
36362
|
+
const destinationId = typeof destination?._id === "string" ? destination._id : void 0;
|
|
36311
36363
|
printCommandEnvelope(
|
|
36312
36364
|
{
|
|
36313
36365
|
catalog: current.catalog,
|
|
36314
36366
|
subscriptions: current.subscriptions,
|
|
36315
36367
|
render: {
|
|
36316
|
-
sections: [
|
|
36368
|
+
sections: [
|
|
36369
|
+
{
|
|
36370
|
+
title: "subscriptions",
|
|
36371
|
+
lines: eventLines(current, destinationId)
|
|
36372
|
+
}
|
|
36373
|
+
]
|
|
36317
36374
|
}
|
|
36318
36375
|
},
|
|
36319
36376
|
{ json: options.json }
|
|
@@ -36322,8 +36379,10 @@ ${eventHelp}
|
|
|
36322
36379
|
subscriptions.command("describe").description("Describe one event from the shared product catalog.").argument("<event>", "Event ID; run subscriptions list to enumerate").option("--json", "Emit JSON output").action(async (eventType, options) => {
|
|
36323
36380
|
const current = await new DeeplineClient().getNotificationSettings();
|
|
36324
36381
|
const event = requireCatalogEvent(current, eventType);
|
|
36382
|
+
const destination = slackDestination(current);
|
|
36383
|
+
const destinationId = typeof destination?._id === "string" ? destination._id : void 0;
|
|
36325
36384
|
const subscription = current.subscriptions.find(
|
|
36326
|
-
(entry) => entry.eventType === event.id
|
|
36385
|
+
(entry) => entry.eventType === event.id && (!destinationId || entry.destinationId === destinationId)
|
|
36327
36386
|
);
|
|
36328
36387
|
printCommandEnvelope(
|
|
36329
36388
|
{
|
|
@@ -36446,9 +36505,22 @@ function notificationByName(settings, reference) {
|
|
|
36446
36505
|
function parseSlackTarget(value) {
|
|
36447
36506
|
const match = /^slack:(.+)$/i.exec(value.trim());
|
|
36448
36507
|
if (!match?.[1]) {
|
|
36449
|
-
throw new Error(
|
|
36508
|
+
throw new Error(
|
|
36509
|
+
"Use --to slack:#channel or --to slack:member:U0123456789."
|
|
36510
|
+
);
|
|
36511
|
+
}
|
|
36512
|
+
const target = match[1].trim();
|
|
36513
|
+
const member = /^member:([UW][A-Z0-9]{8,})$/i.exec(target);
|
|
36514
|
+
if (member?.[1]) return { memberId: member[1].toUpperCase() };
|
|
36515
|
+
if (target.toLowerCase().startsWith("member:")) {
|
|
36516
|
+
throw new Error(
|
|
36517
|
+
"Slack member IDs must look like slack:member:U0123456789."
|
|
36518
|
+
);
|
|
36450
36519
|
}
|
|
36451
|
-
return
|
|
36520
|
+
return { channel: target };
|
|
36521
|
+
}
|
|
36522
|
+
function displaySlackTarget(target) {
|
|
36523
|
+
return `${target.kind === "member" ? "@" : "#"}${target.name}`;
|
|
36452
36524
|
}
|
|
36453
36525
|
function collectEvent(value, previous = []) {
|
|
36454
36526
|
return [...previous, value];
|
|
@@ -36461,10 +36533,11 @@ Examples:
|
|
|
36461
36533
|
deepline notifications events
|
|
36462
36534
|
deepline notifications slack channels --search pipeline
|
|
36463
36535
|
deepline notifications add pipeline-watchdog --to slack:#pipeline-alerts --for play.cron.failed
|
|
36536
|
+
deepline notifications add owner-alerts --to slack:member:U0123456789 --for play.cron.failed
|
|
36464
36537
|
deepline notifications test pipeline-watchdog
|
|
36465
36538
|
|
|
36466
36539
|
Slack connections are managed in Dashboard \u2192 Integrations. This command only
|
|
36467
|
-
chooses the connected Slack channel and the events it receives.
|
|
36540
|
+
chooses the connected Slack channel or member and the events it receives.
|
|
36468
36541
|
`
|
|
36469
36542
|
);
|
|
36470
36543
|
notifications.command("events").description("List the Play events available to a notification.").option("--json", "Emit JSON output").action(async (options) => {
|
|
@@ -36495,7 +36568,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36495
36568
|
id: rule.id,
|
|
36496
36569
|
name: rule.name,
|
|
36497
36570
|
enabled: rule.enabled,
|
|
36498
|
-
target:
|
|
36571
|
+
target: displaySlackTarget(rule.target),
|
|
36499
36572
|
eventTypes: rule.eventTypes
|
|
36500
36573
|
})) : rules,
|
|
36501
36574
|
count: rules.length,
|
|
@@ -36504,7 +36577,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36504
36577
|
{
|
|
36505
36578
|
title: "notifications",
|
|
36506
36579
|
lines: rules.length ? rules.map(
|
|
36507
|
-
(rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192
|
|
36580
|
+
(rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 ${displaySlackTarget(rule.target)} (${rule.eventTypes.join(", ") || "no events"})`
|
|
36508
36581
|
) : [
|
|
36509
36582
|
"None yet. Add one with deepline notifications add <name> --to slack:#channel --for play.cron.failed."
|
|
36510
36583
|
]
|
|
@@ -36524,7 +36597,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36524
36597
|
});
|
|
36525
36598
|
notifications.command("add").argument("<name>", "Short stable name, for example pipeline-watchdog").requiredOption(
|
|
36526
36599
|
"--to <target>",
|
|
36527
|
-
"Target, for example slack:#pipeline-alerts"
|
|
36600
|
+
"Target, for example slack:#pipeline-alerts or slack:member:U0123456789"
|
|
36528
36601
|
).option(
|
|
36529
36602
|
"--for <event>",
|
|
36530
36603
|
"Event ID; repeat for more events. Run notifications events to list them",
|
|
@@ -36535,7 +36608,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36535
36608
|
if (!options.for.length) {
|
|
36536
36609
|
throw new Error("Choose at least one event with --for <event>.");
|
|
36537
36610
|
}
|
|
36538
|
-
const
|
|
36611
|
+
const target = parseSlackTarget(options.to);
|
|
36539
36612
|
if (options.dryRun) {
|
|
36540
36613
|
printCommandEnvelope(
|
|
36541
36614
|
{ dryRun: true, name, target: options.to, eventTypes: options.for },
|
|
@@ -36546,7 +36619,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36546
36619
|
const result = await new DeeplineClient().createNotification({
|
|
36547
36620
|
name,
|
|
36548
36621
|
provider: "slack",
|
|
36549
|
-
|
|
36622
|
+
...target,
|
|
36550
36623
|
eventTypes: options.for
|
|
36551
36624
|
});
|
|
36552
36625
|
printCommandEnvelope(
|
|
@@ -36566,7 +36639,10 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36566
36639
|
);
|
|
36567
36640
|
}
|
|
36568
36641
|
);
|
|
36569
|
-
notifications.command("edit").argument("<name>", "Notification name or ID").option(
|
|
36642
|
+
notifications.command("edit").argument("<name>", "Notification name or ID").option(
|
|
36643
|
+
"--to <target>",
|
|
36644
|
+
"New target, for example slack:#pipeline-alerts or slack:member:U0123456789"
|
|
36645
|
+
).option(
|
|
36570
36646
|
"--for <event>",
|
|
36571
36647
|
"Replace selected events; repeat for more events. Run notifications events to list them",
|
|
36572
36648
|
collectEvent,
|
|
@@ -36575,18 +36651,18 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36575
36651
|
async (name, options) => {
|
|
36576
36652
|
const client2 = new DeeplineClient();
|
|
36577
36653
|
const rule = notificationByName(await client2.getNotifications(), name);
|
|
36578
|
-
const
|
|
36654
|
+
const target = options.to ? parseSlackTarget(options.to) : rule.target.kind === "member" ? { memberId: rule.target.id } : { channel: rule.target.name };
|
|
36579
36655
|
const eventTypes = options.for.length ? options.for : rule.eventTypes;
|
|
36580
36656
|
if (options.dryRun) {
|
|
36581
36657
|
printCommandEnvelope(
|
|
36582
|
-
{ dryRun: true, notification: rule.id,
|
|
36658
|
+
{ dryRun: true, notification: rule.id, target, eventTypes },
|
|
36583
36659
|
{ json: options.json }
|
|
36584
36660
|
);
|
|
36585
36661
|
return;
|
|
36586
36662
|
}
|
|
36587
36663
|
const result = await client2.updateNotification(rule.id, {
|
|
36588
36664
|
name: rule.name,
|
|
36589
|
-
|
|
36665
|
+
...target,
|
|
36590
36666
|
eventTypes
|
|
36591
36667
|
});
|
|
36592
36668
|
printCommandEnvelope({ notification: result }, { json: options.json });
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1033,7 +1033,7 @@ var SDK_RELEASE = {
|
|
|
1033
1033
|
// 0.3.0 introduces raw-v2: complete scrubbed provider responses are
|
|
1034
1034
|
// available at toolResponse.rawV2 while toolResponse.raw and all declared
|
|
1035
1035
|
// getters keep their established compatibility behavior.
|
|
1036
|
-
version: "0.3.
|
|
1036
|
+
version: "0.3.16",
|
|
1037
1037
|
updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
|
|
1038
1038
|
contracts: {
|
|
1039
1039
|
api: {
|
|
@@ -1890,10 +1890,36 @@ var PRODUCT_NOTIFICATION_EVENT_CATALOG = [
|
|
|
1890
1890
|
var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
|
|
1891
1891
|
PRODUCT_NOTIFICATION_EVENT_CATALOG.map((event) => event.id)
|
|
1892
1892
|
);
|
|
1893
|
+
var LEGACY_SLACK_NOTIFICATION_NAME = "Slack notifications";
|
|
1894
|
+
var ProductNotificationLegacySelectionError = class extends Error {
|
|
1895
|
+
constructor(message) {
|
|
1896
|
+
super(message);
|
|
1897
|
+
this.name = "ProductNotificationLegacySelectionError";
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
function resolveLegacySlackNotification(destinations) {
|
|
1901
|
+
const slackDestinations = destinations.filter(
|
|
1902
|
+
(destination) => destination.kind === "slack" && destination.archivedAt === void 0
|
|
1903
|
+
);
|
|
1904
|
+
const canonical = slackDestinations.filter(
|
|
1905
|
+
(destination) => destination.name === LEGACY_SLACK_NOTIFICATION_NAME
|
|
1906
|
+
);
|
|
1907
|
+
if (canonical.length === 1) return canonical[0];
|
|
1908
|
+
if (canonical.length > 1) {
|
|
1909
|
+
throw new ProductNotificationLegacySelectionError(
|
|
1910
|
+
`More than one "${LEGACY_SLACK_NOTIFICATION_NAME}" Slack notification exists. Use the named notification API to choose one.`
|
|
1911
|
+
);
|
|
1912
|
+
}
|
|
1913
|
+
if (slackDestinations.length <= 1) return slackDestinations[0] ?? null;
|
|
1914
|
+
throw new ProductNotificationLegacySelectionError(
|
|
1915
|
+
"More than one Slack notification is configured. Use the named notification API to choose one."
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1893
1918
|
var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
|
|
1894
1919
|
"channels:read",
|
|
1895
1920
|
"chat:write",
|
|
1896
|
-
"groups:read"
|
|
1921
|
+
"groups:read",
|
|
1922
|
+
"im:write"
|
|
1897
1923
|
];
|
|
1898
1924
|
var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
|
|
1899
1925
|
0,
|
|
@@ -5973,9 +5999,12 @@ var DeeplineClient = class {
|
|
|
5973
5999
|
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
5974
6000
|
return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
|
|
5975
6001
|
}
|
|
5976
|
-
/** Select
|
|
5977
|
-
async setNotificationSlack(
|
|
5978
|
-
return this.http.put(
|
|
6002
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
6003
|
+
async setNotificationSlack(destination) {
|
|
6004
|
+
return this.http.put(
|
|
6005
|
+
"/api/v2/settings/notifications",
|
|
6006
|
+
typeof destination === "string" ? { channel: destination } : destination
|
|
6007
|
+
);
|
|
5979
6008
|
}
|
|
5980
6009
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
5981
6010
|
async testNotificationSlack() {
|
|
@@ -36167,11 +36196,23 @@ var eventHelp = PRODUCT_NOTIFICATION_EVENT_CATALOG.map(
|
|
|
36167
36196
|
(event) => ` ${event.id.padEnd(28)} ${event.description}`
|
|
36168
36197
|
).join("\n");
|
|
36169
36198
|
function slackDestination(settings) {
|
|
36170
|
-
|
|
36199
|
+
const destinations = settings.destinations.map(
|
|
36200
|
+
(entry) => ({
|
|
36201
|
+
...entry,
|
|
36202
|
+
kind: typeof entry.kind === "string" ? entry.kind : "",
|
|
36203
|
+
name: typeof entry.name === "string" ? entry.name : "",
|
|
36204
|
+
archivedAt: typeof entry.archivedAt === "number" ? entry.archivedAt : void 0
|
|
36205
|
+
})
|
|
36206
|
+
);
|
|
36207
|
+
return resolveLegacySlackNotification(
|
|
36208
|
+
destinations
|
|
36209
|
+
);
|
|
36171
36210
|
}
|
|
36172
|
-
function eventLines(settings) {
|
|
36211
|
+
function eventLines(settings, destinationId) {
|
|
36173
36212
|
const enabled = new Map(
|
|
36174
|
-
settings.subscriptions.
|
|
36213
|
+
settings.subscriptions.filter(
|
|
36214
|
+
(entry) => !destinationId || entry.destinationId === destinationId
|
|
36215
|
+
).map((entry) => [entry.eventType, entry.enabled])
|
|
36175
36216
|
);
|
|
36176
36217
|
return settings.catalog.map(
|
|
36177
36218
|
(event) => `${event.id}: ${enabled.get(event.id) === true ? "enabled" : "disabled"} \u2014 ${event.description}`
|
|
@@ -36189,6 +36230,7 @@ function requireCatalogEvent(settings, eventType) {
|
|
|
36189
36230
|
async function printSettings(options) {
|
|
36190
36231
|
const settings = await new DeeplineClient().getNotificationSettings();
|
|
36191
36232
|
const slack = slackDestination(settings);
|
|
36233
|
+
const destinationId = typeof slack?._id === "string" ? slack._id : void 0;
|
|
36192
36234
|
printCommandEnvelope(
|
|
36193
36235
|
{
|
|
36194
36236
|
settings,
|
|
@@ -36198,11 +36240,14 @@ async function printSettings(options) {
|
|
|
36198
36240
|
title: "Slack destination",
|
|
36199
36241
|
lines: slack ? [
|
|
36200
36242
|
`status: ${String(slack.status ?? "unknown")}`,
|
|
36201
|
-
|
|
36243
|
+
`${slack.targetKind === "member" ? "member" : "channel"}: ${slack.targetKind === "member" ? "@" : "#"}${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
|
|
36202
36244
|
...slack.lastErrorMessage ? [`issue: ${String(slack.lastErrorMessage)}`] : []
|
|
36203
36245
|
] : ["Not configured."]
|
|
36204
36246
|
},
|
|
36205
|
-
{
|
|
36247
|
+
{
|
|
36248
|
+
title: "subscriptions",
|
|
36249
|
+
lines: eventLines(settings, destinationId)
|
|
36250
|
+
},
|
|
36206
36251
|
{
|
|
36207
36252
|
title: "dead letter queue",
|
|
36208
36253
|
lines: [
|
|
@@ -36302,27 +36347,32 @@ notifications; there is no general integrations CLI.
|
|
|
36302
36347
|
{ json: options.json }
|
|
36303
36348
|
);
|
|
36304
36349
|
});
|
|
36305
|
-
notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").
|
|
36350
|
+
notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").option("--channel <channel>", "Slack channel name or ID").option("--member-id <id>", "Slack member ID, for example U0123456789").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(
|
|
36306
36351
|
async (destination, options) => {
|
|
36307
36352
|
if (destination !== "slack")
|
|
36308
36353
|
throw new Error("Only slack is supported.");
|
|
36354
|
+
if (Boolean(options.channel) === Boolean(options.memberId)) {
|
|
36355
|
+
throw new Error("Provide exactly one of --channel or --member-id.");
|
|
36356
|
+
}
|
|
36357
|
+
const target = options.memberId ? { memberId: options.memberId } : options.channel;
|
|
36309
36358
|
if (options.dryRun) {
|
|
36310
36359
|
printCommandEnvelope(
|
|
36311
|
-
{ dryRun: true, destination,
|
|
36360
|
+
{ dryRun: true, destination, target },
|
|
36312
36361
|
{ json: options.json }
|
|
36313
36362
|
);
|
|
36314
36363
|
return;
|
|
36315
36364
|
}
|
|
36316
|
-
const result = await new DeeplineClient().setNotificationSlack(
|
|
36317
|
-
options.channel
|
|
36318
|
-
);
|
|
36365
|
+
const result = await new DeeplineClient().setNotificationSlack(target);
|
|
36319
36366
|
printCommandEnvelope(
|
|
36320
36367
|
{
|
|
36321
36368
|
ok: true,
|
|
36322
36369
|
result,
|
|
36323
36370
|
render: {
|
|
36324
36371
|
sections: [
|
|
36325
|
-
{
|
|
36372
|
+
{
|
|
36373
|
+
title: "Slack destination saved",
|
|
36374
|
+
lines: [options.memberId ?? options.channel]
|
|
36375
|
+
}
|
|
36326
36376
|
],
|
|
36327
36377
|
actions: [
|
|
36328
36378
|
{
|
|
@@ -36386,12 +36436,19 @@ ${eventHelp}
|
|
|
36386
36436
|
);
|
|
36387
36437
|
subscriptions.command("list").description("List every supported event and its current state.").option("--json", "Emit JSON output").action(async (options) => {
|
|
36388
36438
|
const current = await new DeeplineClient().getNotificationSettings();
|
|
36439
|
+
const destination = slackDestination(current);
|
|
36440
|
+
const destinationId = typeof destination?._id === "string" ? destination._id : void 0;
|
|
36389
36441
|
printCommandEnvelope(
|
|
36390
36442
|
{
|
|
36391
36443
|
catalog: current.catalog,
|
|
36392
36444
|
subscriptions: current.subscriptions,
|
|
36393
36445
|
render: {
|
|
36394
|
-
sections: [
|
|
36446
|
+
sections: [
|
|
36447
|
+
{
|
|
36448
|
+
title: "subscriptions",
|
|
36449
|
+
lines: eventLines(current, destinationId)
|
|
36450
|
+
}
|
|
36451
|
+
]
|
|
36395
36452
|
}
|
|
36396
36453
|
},
|
|
36397
36454
|
{ json: options.json }
|
|
@@ -36400,8 +36457,10 @@ ${eventHelp}
|
|
|
36400
36457
|
subscriptions.command("describe").description("Describe one event from the shared product catalog.").argument("<event>", "Event ID; run subscriptions list to enumerate").option("--json", "Emit JSON output").action(async (eventType, options) => {
|
|
36401
36458
|
const current = await new DeeplineClient().getNotificationSettings();
|
|
36402
36459
|
const event = requireCatalogEvent(current, eventType);
|
|
36460
|
+
const destination = slackDestination(current);
|
|
36461
|
+
const destinationId = typeof destination?._id === "string" ? destination._id : void 0;
|
|
36403
36462
|
const subscription = current.subscriptions.find(
|
|
36404
|
-
(entry) => entry.eventType === event.id
|
|
36463
|
+
(entry) => entry.eventType === event.id && (!destinationId || entry.destinationId === destinationId)
|
|
36405
36464
|
);
|
|
36406
36465
|
printCommandEnvelope(
|
|
36407
36466
|
{
|
|
@@ -36524,9 +36583,22 @@ function notificationByName(settings, reference) {
|
|
|
36524
36583
|
function parseSlackTarget(value) {
|
|
36525
36584
|
const match = /^slack:(.+)$/i.exec(value.trim());
|
|
36526
36585
|
if (!match?.[1]) {
|
|
36527
|
-
throw new Error(
|
|
36586
|
+
throw new Error(
|
|
36587
|
+
"Use --to slack:#channel or --to slack:member:U0123456789."
|
|
36588
|
+
);
|
|
36589
|
+
}
|
|
36590
|
+
const target = match[1].trim();
|
|
36591
|
+
const member = /^member:([UW][A-Z0-9]{8,})$/i.exec(target);
|
|
36592
|
+
if (member?.[1]) return { memberId: member[1].toUpperCase() };
|
|
36593
|
+
if (target.toLowerCase().startsWith("member:")) {
|
|
36594
|
+
throw new Error(
|
|
36595
|
+
"Slack member IDs must look like slack:member:U0123456789."
|
|
36596
|
+
);
|
|
36528
36597
|
}
|
|
36529
|
-
return
|
|
36598
|
+
return { channel: target };
|
|
36599
|
+
}
|
|
36600
|
+
function displaySlackTarget(target) {
|
|
36601
|
+
return `${target.kind === "member" ? "@" : "#"}${target.name}`;
|
|
36530
36602
|
}
|
|
36531
36603
|
function collectEvent(value, previous = []) {
|
|
36532
36604
|
return [...previous, value];
|
|
@@ -36539,10 +36611,11 @@ Examples:
|
|
|
36539
36611
|
deepline notifications events
|
|
36540
36612
|
deepline notifications slack channels --search pipeline
|
|
36541
36613
|
deepline notifications add pipeline-watchdog --to slack:#pipeline-alerts --for play.cron.failed
|
|
36614
|
+
deepline notifications add owner-alerts --to slack:member:U0123456789 --for play.cron.failed
|
|
36542
36615
|
deepline notifications test pipeline-watchdog
|
|
36543
36616
|
|
|
36544
36617
|
Slack connections are managed in Dashboard \u2192 Integrations. This command only
|
|
36545
|
-
chooses the connected Slack channel and the events it receives.
|
|
36618
|
+
chooses the connected Slack channel or member and the events it receives.
|
|
36546
36619
|
`
|
|
36547
36620
|
);
|
|
36548
36621
|
notifications.command("events").description("List the Play events available to a notification.").option("--json", "Emit JSON output").action(async (options) => {
|
|
@@ -36573,7 +36646,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36573
36646
|
id: rule.id,
|
|
36574
36647
|
name: rule.name,
|
|
36575
36648
|
enabled: rule.enabled,
|
|
36576
|
-
target:
|
|
36649
|
+
target: displaySlackTarget(rule.target),
|
|
36577
36650
|
eventTypes: rule.eventTypes
|
|
36578
36651
|
})) : rules,
|
|
36579
36652
|
count: rules.length,
|
|
@@ -36582,7 +36655,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36582
36655
|
{
|
|
36583
36656
|
title: "notifications",
|
|
36584
36657
|
lines: rules.length ? rules.map(
|
|
36585
|
-
(rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192
|
|
36658
|
+
(rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 ${displaySlackTarget(rule.target)} (${rule.eventTypes.join(", ") || "no events"})`
|
|
36586
36659
|
) : [
|
|
36587
36660
|
"None yet. Add one with deepline notifications add <name> --to slack:#channel --for play.cron.failed."
|
|
36588
36661
|
]
|
|
@@ -36602,7 +36675,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36602
36675
|
});
|
|
36603
36676
|
notifications.command("add").argument("<name>", "Short stable name, for example pipeline-watchdog").requiredOption(
|
|
36604
36677
|
"--to <target>",
|
|
36605
|
-
"Target, for example slack:#pipeline-alerts"
|
|
36678
|
+
"Target, for example slack:#pipeline-alerts or slack:member:U0123456789"
|
|
36606
36679
|
).option(
|
|
36607
36680
|
"--for <event>",
|
|
36608
36681
|
"Event ID; repeat for more events. Run notifications events to list them",
|
|
@@ -36613,7 +36686,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36613
36686
|
if (!options.for.length) {
|
|
36614
36687
|
throw new Error("Choose at least one event with --for <event>.");
|
|
36615
36688
|
}
|
|
36616
|
-
const
|
|
36689
|
+
const target = parseSlackTarget(options.to);
|
|
36617
36690
|
if (options.dryRun) {
|
|
36618
36691
|
printCommandEnvelope(
|
|
36619
36692
|
{ dryRun: true, name, target: options.to, eventTypes: options.for },
|
|
@@ -36624,7 +36697,7 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36624
36697
|
const result = await new DeeplineClient().createNotification({
|
|
36625
36698
|
name,
|
|
36626
36699
|
provider: "slack",
|
|
36627
|
-
|
|
36700
|
+
...target,
|
|
36628
36701
|
eventTypes: options.for
|
|
36629
36702
|
});
|
|
36630
36703
|
printCommandEnvelope(
|
|
@@ -36644,7 +36717,10 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36644
36717
|
);
|
|
36645
36718
|
}
|
|
36646
36719
|
);
|
|
36647
|
-
notifications.command("edit").argument("<name>", "Notification name or ID").option(
|
|
36720
|
+
notifications.command("edit").argument("<name>", "Notification name or ID").option(
|
|
36721
|
+
"--to <target>",
|
|
36722
|
+
"New target, for example slack:#pipeline-alerts or slack:member:U0123456789"
|
|
36723
|
+
).option(
|
|
36648
36724
|
"--for <event>",
|
|
36649
36725
|
"Replace selected events; repeat for more events. Run notifications events to list them",
|
|
36650
36726
|
collectEvent,
|
|
@@ -36653,18 +36729,18 @@ chooses the connected Slack channel and the events it receives.
|
|
|
36653
36729
|
async (name, options) => {
|
|
36654
36730
|
const client2 = new DeeplineClient();
|
|
36655
36731
|
const rule = notificationByName(await client2.getNotifications(), name);
|
|
36656
|
-
const
|
|
36732
|
+
const target = options.to ? parseSlackTarget(options.to) : rule.target.kind === "member" ? { memberId: rule.target.id } : { channel: rule.target.name };
|
|
36657
36733
|
const eventTypes = options.for.length ? options.for : rule.eventTypes;
|
|
36658
36734
|
if (options.dryRun) {
|
|
36659
36735
|
printCommandEnvelope(
|
|
36660
|
-
{ dryRun: true, notification: rule.id,
|
|
36736
|
+
{ dryRun: true, notification: rule.id, target, eventTypes },
|
|
36661
36737
|
{ json: options.json }
|
|
36662
36738
|
);
|
|
36663
36739
|
return;
|
|
36664
36740
|
}
|
|
36665
36741
|
const result = await client2.updateNotification(rule.id, {
|
|
36666
36742
|
name: rule.name,
|
|
36667
|
-
|
|
36743
|
+
...target,
|
|
36668
36744
|
eventTypes
|
|
36669
36745
|
});
|
|
36670
36746
|
printCommandEnvelope({ notification: result }, { json: options.json });
|
package/dist/index.d.mts
CHANGED
|
@@ -1243,6 +1243,7 @@ interface ProductNotification {
|
|
|
1243
1243
|
target: {
|
|
1244
1244
|
id: string;
|
|
1245
1245
|
name: string;
|
|
1246
|
+
kind?: 'channel' | 'member';
|
|
1246
1247
|
};
|
|
1247
1248
|
enabled: boolean;
|
|
1248
1249
|
status: string;
|
|
@@ -1894,6 +1895,24 @@ type EnrichCompiledConfig = {
|
|
|
1894
1895
|
};
|
|
1895
1896
|
};
|
|
1896
1897
|
|
|
1898
|
+
type SlackNotificationTarget = {
|
|
1899
|
+
channel: string;
|
|
1900
|
+
memberId?: never;
|
|
1901
|
+
} | {
|
|
1902
|
+
channel?: never;
|
|
1903
|
+
memberId: string;
|
|
1904
|
+
};
|
|
1905
|
+
type CreateNotificationInput = {
|
|
1906
|
+
name: string;
|
|
1907
|
+
provider: 'slack';
|
|
1908
|
+
eventTypes: string[];
|
|
1909
|
+
} & SlackNotificationTarget;
|
|
1910
|
+
type UpdateNotificationInput = {
|
|
1911
|
+
enabled: boolean;
|
|
1912
|
+
} | ({
|
|
1913
|
+
name: string;
|
|
1914
|
+
eventTypes: string[];
|
|
1915
|
+
} & SlackNotificationTarget);
|
|
1897
1916
|
type IngestionStorageRepairResult = {
|
|
1898
1917
|
status?: 'repaired';
|
|
1899
1918
|
connection_grants: {
|
|
@@ -3364,8 +3383,10 @@ declare class DeeplineClient {
|
|
|
3364
3383
|
isPrivate: boolean;
|
|
3365
3384
|
}>;
|
|
3366
3385
|
}>;
|
|
3367
|
-
/** Select
|
|
3368
|
-
setNotificationSlack(
|
|
3386
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
3387
|
+
setNotificationSlack(destination: string | {
|
|
3388
|
+
memberId: string;
|
|
3389
|
+
}): Promise<unknown>;
|
|
3369
3390
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
3370
3391
|
testNotificationSlack(): Promise<{
|
|
3371
3392
|
ok: boolean;
|
|
@@ -3398,20 +3419,9 @@ declare class DeeplineClient {
|
|
|
3398
3419
|
}>;
|
|
3399
3420
|
}>;
|
|
3400
3421
|
/** Create a named notification routed through an existing provider integration. */
|
|
3401
|
-
createNotification(input:
|
|
3402
|
-
name: string;
|
|
3403
|
-
provider: 'slack';
|
|
3404
|
-
channel: string;
|
|
3405
|
-
eventTypes: string[];
|
|
3406
|
-
}): Promise<unknown>;
|
|
3422
|
+
createNotification(input: CreateNotificationInput): Promise<unknown>;
|
|
3407
3423
|
/** Update a notification's target, event selection, or enabled state. */
|
|
3408
|
-
updateNotification(notificationId: string, input:
|
|
3409
|
-
enabled: boolean;
|
|
3410
|
-
} | {
|
|
3411
|
-
name: string;
|
|
3412
|
-
channel: string;
|
|
3413
|
-
eventTypes: string[];
|
|
3414
|
-
}): Promise<unknown>;
|
|
3424
|
+
updateNotification(notificationId: string, input: UpdateNotificationInput): Promise<unknown>;
|
|
3415
3425
|
/** Send a validation ping to one notification. */
|
|
3416
3426
|
testNotification(notificationId: string): Promise<{
|
|
3417
3427
|
ok: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -1243,6 +1243,7 @@ interface ProductNotification {
|
|
|
1243
1243
|
target: {
|
|
1244
1244
|
id: string;
|
|
1245
1245
|
name: string;
|
|
1246
|
+
kind?: 'channel' | 'member';
|
|
1246
1247
|
};
|
|
1247
1248
|
enabled: boolean;
|
|
1248
1249
|
status: string;
|
|
@@ -1894,6 +1895,24 @@ type EnrichCompiledConfig = {
|
|
|
1894
1895
|
};
|
|
1895
1896
|
};
|
|
1896
1897
|
|
|
1898
|
+
type SlackNotificationTarget = {
|
|
1899
|
+
channel: string;
|
|
1900
|
+
memberId?: never;
|
|
1901
|
+
} | {
|
|
1902
|
+
channel?: never;
|
|
1903
|
+
memberId: string;
|
|
1904
|
+
};
|
|
1905
|
+
type CreateNotificationInput = {
|
|
1906
|
+
name: string;
|
|
1907
|
+
provider: 'slack';
|
|
1908
|
+
eventTypes: string[];
|
|
1909
|
+
} & SlackNotificationTarget;
|
|
1910
|
+
type UpdateNotificationInput = {
|
|
1911
|
+
enabled: boolean;
|
|
1912
|
+
} | ({
|
|
1913
|
+
name: string;
|
|
1914
|
+
eventTypes: string[];
|
|
1915
|
+
} & SlackNotificationTarget);
|
|
1897
1916
|
type IngestionStorageRepairResult = {
|
|
1898
1917
|
status?: 'repaired';
|
|
1899
1918
|
connection_grants: {
|
|
@@ -3364,8 +3383,10 @@ declare class DeeplineClient {
|
|
|
3364
3383
|
isPrivate: boolean;
|
|
3365
3384
|
}>;
|
|
3366
3385
|
}>;
|
|
3367
|
-
/** Select
|
|
3368
|
-
setNotificationSlack(
|
|
3386
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
3387
|
+
setNotificationSlack(destination: string | {
|
|
3388
|
+
memberId: string;
|
|
3389
|
+
}): Promise<unknown>;
|
|
3369
3390
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
3370
3391
|
testNotificationSlack(): Promise<{
|
|
3371
3392
|
ok: boolean;
|
|
@@ -3398,20 +3419,9 @@ declare class DeeplineClient {
|
|
|
3398
3419
|
}>;
|
|
3399
3420
|
}>;
|
|
3400
3421
|
/** Create a named notification routed through an existing provider integration. */
|
|
3401
|
-
createNotification(input:
|
|
3402
|
-
name: string;
|
|
3403
|
-
provider: 'slack';
|
|
3404
|
-
channel: string;
|
|
3405
|
-
eventTypes: string[];
|
|
3406
|
-
}): Promise<unknown>;
|
|
3422
|
+
createNotification(input: CreateNotificationInput): Promise<unknown>;
|
|
3407
3423
|
/** Update a notification's target, event selection, or enabled state. */
|
|
3408
|
-
updateNotification(notificationId: string, input:
|
|
3409
|
-
enabled: boolean;
|
|
3410
|
-
} | {
|
|
3411
|
-
name: string;
|
|
3412
|
-
channel: string;
|
|
3413
|
-
eventTypes: string[];
|
|
3414
|
-
}): Promise<unknown>;
|
|
3424
|
+
updateNotification(notificationId: string, input: UpdateNotificationInput): Promise<unknown>;
|
|
3415
3425
|
/** Send a validation ping to one notification. */
|
|
3416
3426
|
testNotification(notificationId: string): Promise<{
|
|
3417
3427
|
ok: boolean;
|
package/dist/index.js
CHANGED
|
@@ -783,7 +783,7 @@ var SDK_RELEASE = {
|
|
|
783
783
|
// 0.3.0 introduces raw-v2: complete scrubbed provider responses are
|
|
784
784
|
// available at toolResponse.rawV2 while toolResponse.raw and all declared
|
|
785
785
|
// getters keep their established compatibility behavior.
|
|
786
|
-
version: "0.3.
|
|
786
|
+
version: "0.3.16",
|
|
787
787
|
updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
|
|
788
788
|
contracts: {
|
|
789
789
|
api: {
|
|
@@ -1643,7 +1643,8 @@ var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
|
|
|
1643
1643
|
var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
|
|
1644
1644
|
"channels:read",
|
|
1645
1645
|
"chat:write",
|
|
1646
|
-
"groups:read"
|
|
1646
|
+
"groups:read",
|
|
1647
|
+
"im:write"
|
|
1647
1648
|
];
|
|
1648
1649
|
var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
|
|
1649
1650
|
0,
|
|
@@ -5723,9 +5724,12 @@ var DeeplineClient = class {
|
|
|
5723
5724
|
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
5724
5725
|
return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
|
|
5725
5726
|
}
|
|
5726
|
-
/** Select
|
|
5727
|
-
async setNotificationSlack(
|
|
5728
|
-
return this.http.put(
|
|
5727
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
5728
|
+
async setNotificationSlack(destination) {
|
|
5729
|
+
return this.http.put(
|
|
5730
|
+
"/api/v2/settings/notifications",
|
|
5731
|
+
typeof destination === "string" ? { channel: destination } : destination
|
|
5732
|
+
);
|
|
5729
5733
|
}
|
|
5730
5734
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
5731
5735
|
async testNotificationSlack() {
|
package/dist/index.mjs
CHANGED
|
@@ -706,7 +706,7 @@ var SDK_RELEASE = {
|
|
|
706
706
|
// 0.3.0 introduces raw-v2: complete scrubbed provider responses are
|
|
707
707
|
// available at toolResponse.rawV2 while toolResponse.raw and all declared
|
|
708
708
|
// getters keep their established compatibility behavior.
|
|
709
|
-
version: "0.3.
|
|
709
|
+
version: "0.3.16",
|
|
710
710
|
updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
|
|
711
711
|
contracts: {
|
|
712
712
|
api: {
|
|
@@ -1566,7 +1566,8 @@ var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
|
|
|
1566
1566
|
var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
|
|
1567
1567
|
"channels:read",
|
|
1568
1568
|
"chat:write",
|
|
1569
|
-
"groups:read"
|
|
1569
|
+
"groups:read",
|
|
1570
|
+
"im:write"
|
|
1570
1571
|
];
|
|
1571
1572
|
var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
|
|
1572
1573
|
0,
|
|
@@ -5646,9 +5647,12 @@ var DeeplineClient = class {
|
|
|
5646
5647
|
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
5647
5648
|
return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
|
|
5648
5649
|
}
|
|
5649
|
-
/** Select
|
|
5650
|
-
async setNotificationSlack(
|
|
5651
|
-
return this.http.put(
|
|
5650
|
+
/** Select a Slack channel or direct member used for product notifications. */
|
|
5651
|
+
async setNotificationSlack(destination) {
|
|
5652
|
+
return this.http.put(
|
|
5653
|
+
"/api/v2/settings/notifications",
|
|
5654
|
+
typeof destination === "string" ? { channel: destination } : destination
|
|
5655
|
+
);
|
|
5652
5656
|
}
|
|
5653
5657
|
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
5654
5658
|
async testNotificationSlack() {
|