@objectstack/connector-slack 7.4.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.
@@ -0,0 +1,22 @@
1
+
2
+ > @objectstack/connector-slack@7.4.0 build /home/runner/work/framework/framework/packages/connectors/connector-slack
3
+ > tsup --config ../../../tsup.config.ts
4
+
5
+ CLI Building entry: src/index.ts
6
+ CLI Using tsconfig: tsconfig.json
7
+ CLI tsup v8.5.1
8
+ CLI Using tsup config: /home/runner/work/framework/framework/tsup.config.ts
9
+ CLI Target: es2020
10
+ CLI Cleaning output folder
11
+ ESM Build start
12
+ CJS Build start
13
+ ESM dist/index.mjs 5.34 KB
14
+ ESM dist/index.mjs.map 15.18 KB
15
+ ESM ⚡️ Build success in 137ms
16
+ CJS dist/index.js 6.42 KB
17
+ CJS dist/index.js.map 16.33 KB
18
+ CJS ⚡️ Build success in 148ms
19
+ DTS Build start
20
+ DTS ⚡️ Build success in 14590ms
21
+ DTS dist/index.d.mts 4.81 KB
22
+ DTS dist/index.d.ts 4.81 KB
package/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # @objectstack/connector-slack
2
+
3
+ ## 7.4.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [23c7107]
8
+ - Updated dependencies [c72daad]
9
+ - Updated dependencies [f115182]
10
+ - Updated dependencies [2faf9f2]
11
+ - Updated dependencies [2faf9f2]
12
+ - Updated dependencies [2faf9f2]
13
+ - Updated dependencies [58b450b]
14
+ - Updated dependencies [82eb6cf]
15
+ - Updated dependencies [13d8653]
16
+ - Updated dependencies [ff3d006]
17
+ - Updated dependencies [5e831de]
18
+ - @objectstack/spec@7.4.0
19
+ - @objectstack/core@7.4.0
package/LICENSE ADDED
@@ -0,0 +1,93 @@
1
+ License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
2
+ "Business Source License" is a trademark of MariaDB Corporation Ab.
3
+
4
+ Parameters
5
+
6
+ Licensor: ObjectStack AI LLC
7
+ Licensed Work: ObjectStack Runtime: the BSL-licensed packages
8
+ of the ObjectStack monorepo as listed in LICENSING.md.
9
+ Copyright (c) 2026 ObjectStack AI LLC.
10
+ Additional Use Grant: You may make production use of the Licensed Work, provided
11
+ Your use does not include offering the Licensed Work to third
12
+ parties on a hosted or embedded basis in order to compete with
13
+ ObjectStack AI LLC's paid version(s) of the Licensed Work. For purposes
14
+ of this license:
15
+
16
+ A "competitive offering" is a Product that is offered to third
17
+ parties on a paid basis, including through paid support
18
+ arrangements, that significantly overlaps with the capabilities
19
+ of ObjectStack AI LLC's paid version(s) of the Licensed Work. If Your
20
+ Product is not a competitive offering when You first make it
21
+ generally available, it will not become a competitive offering
22
+ later due to ObjectStack AI LLC releasing a new version of the Licensed
23
+ Work with additional capabilities. In addition, Products that
24
+ are not provided on a paid basis are not competitive.
25
+
26
+ "Product" means software that is offered to end users to manage
27
+ in their own environments or offered as a service on a hosted
28
+ basis.
29
+
30
+ "Embedded" means including the source code or executable code
31
+ from the Licensed Work in a competitive offering. "Embedded"
32
+ also means packaging the competitive offering in such a way
33
+ that the Licensed Work must be accessed or downloaded for the
34
+ competitive offering to operate.
35
+
36
+ Hosting or using the Licensed Work(s) for internal purposes
37
+ within an organization is not considered a competitive
38
+ offering. ObjectStack AI LLC considers your organization to include all
39
+ of your affiliates under common control.
40
+
41
+ For binding interpretive guidance on using ObjectStack AI LLC products
42
+ under the Business Source License, please visit our FAQ.
43
+ (see LICENSING.md in this repository)
44
+ Change Date: Four years from the date the Licensed Work is published.
45
+ Change License: Apache License, Version 2.0
46
+
47
+ For information about alternative licensing arrangements for the Licensed Work,
48
+ please contact licensing@objectstack.dev.
49
+
50
+ Notice
51
+
52
+ Business Source License 1.1
53
+
54
+ Terms
55
+
56
+ The Licensor hereby grants you the right to copy, modify, create derivative
57
+ works, redistribute, and make non-production use of the Licensed Work. The
58
+ Licensor may make an Additional Use Grant, above, permitting limited production use.
59
+
60
+ Effective on the Change Date, or the fourth anniversary of the first publicly
61
+ available distribution of a specific version of the Licensed Work under this
62
+ License, whichever comes first, the Licensor hereby grants you rights under
63
+ the terms of the Change License, and the rights granted in the paragraph
64
+ above terminate.
65
+
66
+ If your use of the Licensed Work does not comply with the requirements
67
+ currently in effect as described in this License, you must purchase a
68
+ commercial license from the Licensor, its affiliated entities, or authorized
69
+ resellers, or you must refrain from using the Licensed Work.
70
+
71
+ All copies of the original and modified Licensed Work, and derivative works
72
+ of the Licensed Work, are subject to this License. This License applies
73
+ separately for each version of the Licensed Work and the Change Date may vary
74
+ for each version of the Licensed Work released by Licensor.
75
+
76
+ You must conspicuously display this License on each original or modified copy
77
+ of the Licensed Work. If you receive the Licensed Work in original or
78
+ modified form from a third party, the terms and conditions set forth in this
79
+ License apply to your use of that work.
80
+
81
+ Any use of the Licensed Work in violation of this License will automatically
82
+ terminate your rights under this License for the current and all other
83
+ versions of the Licensed Work.
84
+
85
+ This License does not grant you any right in any trademark or logo of
86
+ Licensor or its affiliates (provided that you may use a trademark or logo of
87
+ Licensor as expressly required by this License).
88
+
89
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
90
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
91
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
92
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
93
+ TITLE.
@@ -0,0 +1,105 @@
1
+ import { Connector } from '@objectstack/spec/integration';
2
+ import { Plugin, PluginContext } from '@objectstack/core';
3
+
4
+ /**
5
+ * Slack connector — a *concrete* connector (ADR-0018 §Addendum) and the second
6
+ * reference implementation after `@objectstack/connector-rest`. It produces a
7
+ * {@link Connector} definition plus handlers for a small set of Slack Web API
8
+ * actions, which the baseline `connector_action` node dispatches to.
9
+ *
10
+ * Scope (ADR-0022 "raw API call" path): this is the *integration mechanism*
11
+ * for talking to Slack's API — "post this exact text to this channel". It is
12
+ * deliberately **not** the human-notification layer: there is no preference
13
+ * matrix, inbox, outbox, or thread/session semantics here. Those belong to a
14
+ * `MessagingChannel` (ADR-0012/0013), which may itself delegate its transport
15
+ * to this connector.
16
+ *
17
+ * Open-source scope: **static** auth only — a Slack **bot token** (`xoxb-…`),
18
+ * supplied by the caller and sent as a bearer credential. OAuth2 install/refresh,
19
+ * credential vaulting, and multi-tenant connection lifecycle are the enterprise
20
+ * tier (see `../cloud/docs/design/connector-tiering.md`) and are out of scope.
21
+ *
22
+ * Slack quirk: the Web API returns HTTP `200` even on logical failure, with the
23
+ * real outcome in the JSON body's `ok` field (and `error` on failure). Handlers
24
+ * therefore surface `ok` from the payload, not from the HTTP status, and never
25
+ * throw on a logical failure — the flow author branches on `${node.ok}`.
26
+ */
27
+ interface SlackConnectorOptions {
28
+ /** Connector machine name (snake_case). Defaults to `slack`. */
29
+ name?: string;
30
+ /** Human-readable label. Defaults to `Slack`. */
31
+ label?: string;
32
+ /** Slack bot token (`xoxb-…`), sent as `Authorization: Bearer <token>`. */
33
+ token: string;
34
+ /** Web API base URL. Defaults to `https://slack.com/api`. */
35
+ baseUrl?: string;
36
+ /** Headers merged into every request (request-level headers win). */
37
+ defaultHeaders?: Record<string, string>;
38
+ /** Injected for tests; defaults to the global `fetch`. */
39
+ fetchImpl?: typeof fetch;
40
+ }
41
+ /** Input accepted by `chat.postMessage`. */
42
+ interface SlackPostMessageInput {
43
+ /** Channel id (`C…`), user id (`U…`), or channel name (`#general`). */
44
+ channel: string;
45
+ /** Message text (fallback when `blocks` are present). */
46
+ text?: string;
47
+ /** Thread root `ts` to reply into an existing thread. */
48
+ thread_ts?: string;
49
+ /** Block Kit blocks. */
50
+ blocks?: unknown[];
51
+ [key: string]: unknown;
52
+ }
53
+ /** Generic Slack Web API result envelope. */
54
+ interface SlackResult {
55
+ /** Slack's logical success flag (from the JSON body, not the HTTP status). */
56
+ ok: boolean;
57
+ /** HTTP status (almost always 200 for the Slack Web API). */
58
+ status: number;
59
+ /** Full parsed Slack payload. */
60
+ body: Record<string, unknown>;
61
+ /** Slack error code when `ok` is false (e.g. `channel_not_found`). */
62
+ error?: string;
63
+ }
64
+ /** A connector definition paired with its action handlers, ready for registerConnector(). */
65
+ interface SlackConnectorBundle {
66
+ def: Connector;
67
+ handlers: Record<string, (input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>>;
68
+ }
69
+ declare function createSlackConnector(opts: SlackConnectorOptions): SlackConnectorBundle;
70
+
71
+ /**
72
+ * Minimal surface of the automation engine this plugin depends on — the
73
+ * connector registry from ADR-0018 §Addendum. Kept structural so the plugin
74
+ * needs no runtime dependency on `@objectstack/service-automation`.
75
+ */
76
+ interface ConnectorRegistrySurface {
77
+ registerConnector(def: Connector, handlers: Record<string, (input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>>): void;
78
+ unregisterConnector(name: string): void;
79
+ }
80
+ interface ConnectorSlackPluginOptions extends SlackConnectorOptions {
81
+ }
82
+ /**
83
+ * ConnectorSlackPlugin — registers a Slack Web API connector on the automation
84
+ * engine. The second reference concrete connector (ADR-0018 §Addendum); it
85
+ * enables the ADR-0022 "raw API call" path — a flow's `connector_action` step
86
+ * can dispatch to `slack.chat.postMessage` without the messaging stack.
87
+ *
88
+ * If no automation engine is present the plugin logs and skips — the connector
89
+ * has nowhere to register, which is not an error.
90
+ */
91
+ declare class ConnectorSlackPlugin implements Plugin {
92
+ name: string;
93
+ version: string;
94
+ type: "standard";
95
+ dependencies: string[];
96
+ private readonly options;
97
+ private connectorName?;
98
+ private automation?;
99
+ constructor(options: ConnectorSlackPluginOptions);
100
+ init(_ctx: PluginContext): Promise<void>;
101
+ start(ctx: PluginContext): Promise<void>;
102
+ stop(_ctx: PluginContext): Promise<void>;
103
+ }
104
+
105
+ export { type ConnectorRegistrySurface, ConnectorSlackPlugin, type ConnectorSlackPluginOptions, type SlackConnectorBundle, type SlackConnectorOptions, type SlackPostMessageInput, type SlackResult, createSlackConnector };
@@ -0,0 +1,105 @@
1
+ import { Connector } from '@objectstack/spec/integration';
2
+ import { Plugin, PluginContext } from '@objectstack/core';
3
+
4
+ /**
5
+ * Slack connector — a *concrete* connector (ADR-0018 §Addendum) and the second
6
+ * reference implementation after `@objectstack/connector-rest`. It produces a
7
+ * {@link Connector} definition plus handlers for a small set of Slack Web API
8
+ * actions, which the baseline `connector_action` node dispatches to.
9
+ *
10
+ * Scope (ADR-0022 "raw API call" path): this is the *integration mechanism*
11
+ * for talking to Slack's API — "post this exact text to this channel". It is
12
+ * deliberately **not** the human-notification layer: there is no preference
13
+ * matrix, inbox, outbox, or thread/session semantics here. Those belong to a
14
+ * `MessagingChannel` (ADR-0012/0013), which may itself delegate its transport
15
+ * to this connector.
16
+ *
17
+ * Open-source scope: **static** auth only — a Slack **bot token** (`xoxb-…`),
18
+ * supplied by the caller and sent as a bearer credential. OAuth2 install/refresh,
19
+ * credential vaulting, and multi-tenant connection lifecycle are the enterprise
20
+ * tier (see `../cloud/docs/design/connector-tiering.md`) and are out of scope.
21
+ *
22
+ * Slack quirk: the Web API returns HTTP `200` even on logical failure, with the
23
+ * real outcome in the JSON body's `ok` field (and `error` on failure). Handlers
24
+ * therefore surface `ok` from the payload, not from the HTTP status, and never
25
+ * throw on a logical failure — the flow author branches on `${node.ok}`.
26
+ */
27
+ interface SlackConnectorOptions {
28
+ /** Connector machine name (snake_case). Defaults to `slack`. */
29
+ name?: string;
30
+ /** Human-readable label. Defaults to `Slack`. */
31
+ label?: string;
32
+ /** Slack bot token (`xoxb-…`), sent as `Authorization: Bearer <token>`. */
33
+ token: string;
34
+ /** Web API base URL. Defaults to `https://slack.com/api`. */
35
+ baseUrl?: string;
36
+ /** Headers merged into every request (request-level headers win). */
37
+ defaultHeaders?: Record<string, string>;
38
+ /** Injected for tests; defaults to the global `fetch`. */
39
+ fetchImpl?: typeof fetch;
40
+ }
41
+ /** Input accepted by `chat.postMessage`. */
42
+ interface SlackPostMessageInput {
43
+ /** Channel id (`C…`), user id (`U…`), or channel name (`#general`). */
44
+ channel: string;
45
+ /** Message text (fallback when `blocks` are present). */
46
+ text?: string;
47
+ /** Thread root `ts` to reply into an existing thread. */
48
+ thread_ts?: string;
49
+ /** Block Kit blocks. */
50
+ blocks?: unknown[];
51
+ [key: string]: unknown;
52
+ }
53
+ /** Generic Slack Web API result envelope. */
54
+ interface SlackResult {
55
+ /** Slack's logical success flag (from the JSON body, not the HTTP status). */
56
+ ok: boolean;
57
+ /** HTTP status (almost always 200 for the Slack Web API). */
58
+ status: number;
59
+ /** Full parsed Slack payload. */
60
+ body: Record<string, unknown>;
61
+ /** Slack error code when `ok` is false (e.g. `channel_not_found`). */
62
+ error?: string;
63
+ }
64
+ /** A connector definition paired with its action handlers, ready for registerConnector(). */
65
+ interface SlackConnectorBundle {
66
+ def: Connector;
67
+ handlers: Record<string, (input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>>;
68
+ }
69
+ declare function createSlackConnector(opts: SlackConnectorOptions): SlackConnectorBundle;
70
+
71
+ /**
72
+ * Minimal surface of the automation engine this plugin depends on — the
73
+ * connector registry from ADR-0018 §Addendum. Kept structural so the plugin
74
+ * needs no runtime dependency on `@objectstack/service-automation`.
75
+ */
76
+ interface ConnectorRegistrySurface {
77
+ registerConnector(def: Connector, handlers: Record<string, (input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>>): void;
78
+ unregisterConnector(name: string): void;
79
+ }
80
+ interface ConnectorSlackPluginOptions extends SlackConnectorOptions {
81
+ }
82
+ /**
83
+ * ConnectorSlackPlugin — registers a Slack Web API connector on the automation
84
+ * engine. The second reference concrete connector (ADR-0018 §Addendum); it
85
+ * enables the ADR-0022 "raw API call" path — a flow's `connector_action` step
86
+ * can dispatch to `slack.chat.postMessage` without the messaging stack.
87
+ *
88
+ * If no automation engine is present the plugin logs and skips — the connector
89
+ * has nowhere to register, which is not an error.
90
+ */
91
+ declare class ConnectorSlackPlugin implements Plugin {
92
+ name: string;
93
+ version: string;
94
+ type: "standard";
95
+ dependencies: string[];
96
+ private readonly options;
97
+ private connectorName?;
98
+ private automation?;
99
+ constructor(options: ConnectorSlackPluginOptions);
100
+ init(_ctx: PluginContext): Promise<void>;
101
+ start(ctx: PluginContext): Promise<void>;
102
+ stop(_ctx: PluginContext): Promise<void>;
103
+ }
104
+
105
+ export { type ConnectorRegistrySurface, ConnectorSlackPlugin, type ConnectorSlackPluginOptions, type SlackConnectorBundle, type SlackConnectorOptions, type SlackPostMessageInput, type SlackResult, createSlackConnector };
package/dist/index.js ADDED
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ConnectorSlackPlugin: () => ConnectorSlackPlugin,
24
+ createSlackConnector: () => createSlackConnector
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/slack-connector.ts
29
+ function createSlackConnector(opts) {
30
+ const name = opts.name ?? "slack";
31
+ const baseUrl = (opts.baseUrl ?? "https://slack.com/api").replace(/\/+$/, "");
32
+ const doFetch = opts.fetchImpl ?? fetch;
33
+ const def = {
34
+ name,
35
+ label: opts.label ?? "Slack",
36
+ type: "api",
37
+ description: "Slack Web API connector (static bot-token auth). Post and update messages, or call any Web API method.",
38
+ icon: "slack",
39
+ authentication: { type: "bearer", token: opts.token },
40
+ // Defaulted by ConnectorSchema; set explicitly so the literal satisfies
41
+ // the (post-parse) Connector output type.
42
+ status: "active",
43
+ enabled: true,
44
+ connectionTimeoutMs: 3e4,
45
+ requestTimeoutMs: 3e4,
46
+ actions: [
47
+ {
48
+ key: "chat.postMessage",
49
+ label: "Post Message",
50
+ description: "Post a message to a channel, DM, or thread (Slack chat.postMessage).",
51
+ inputSchema: {
52
+ type: "object",
53
+ required: ["channel"],
54
+ properties: {
55
+ channel: { type: "string", description: "Channel id, user id, or #name" },
56
+ text: { type: "string", description: "Message text" },
57
+ thread_ts: { type: "string", description: "Thread root ts to reply into" },
58
+ blocks: { type: "array", description: "Block Kit blocks" }
59
+ }
60
+ },
61
+ outputSchema: slackOutputSchema()
62
+ },
63
+ {
64
+ key: "chat.update",
65
+ label: "Update Message",
66
+ description: "Edit an existing message (Slack chat.update).",
67
+ inputSchema: {
68
+ type: "object",
69
+ required: ["channel", "ts"],
70
+ properties: {
71
+ channel: { type: "string", description: "Channel id" },
72
+ ts: { type: "string", description: "Timestamp of the message to update" },
73
+ text: { type: "string", description: "New message text" },
74
+ blocks: { type: "array", description: "New Block Kit blocks" }
75
+ }
76
+ },
77
+ outputSchema: slackOutputSchema()
78
+ },
79
+ {
80
+ key: "call",
81
+ label: "Call Web API Method",
82
+ description: "Escape hatch \u2014 call any Slack Web API method with arbitrary params.",
83
+ inputSchema: {
84
+ type: "object",
85
+ required: ["method"],
86
+ properties: {
87
+ method: { type: "string", description: "Web API method, e.g. conversations.list" },
88
+ params: { type: "object", description: "Method parameters (JSON body)" }
89
+ }
90
+ },
91
+ outputSchema: slackOutputSchema()
92
+ }
93
+ ]
94
+ };
95
+ async function callSlack(method, params) {
96
+ const headers = {
97
+ "Content-Type": "application/json; charset=utf-8",
98
+ ...opts.defaultHeaders,
99
+ Authorization: `Bearer ${opts.token}`
100
+ };
101
+ const response = await doFetch(`${baseUrl}/${method}`, {
102
+ method: "POST",
103
+ headers,
104
+ body: JSON.stringify(params)
105
+ });
106
+ const body = await response.json();
107
+ const ok = body.ok === true;
108
+ return {
109
+ ok,
110
+ status: response.status,
111
+ body,
112
+ error: ok ? void 0 : body.error
113
+ };
114
+ }
115
+ async function postMessage(input) {
116
+ return toRecord(await callSlack("chat.postMessage", input));
117
+ }
118
+ async function update(input) {
119
+ return toRecord(await callSlack("chat.update", input));
120
+ }
121
+ async function call(input) {
122
+ const method = String(input.method ?? "");
123
+ if (!method) throw new Error("slack 'call' action: 'method' is required");
124
+ const params = input.params ?? {};
125
+ return toRecord(await callSlack(method, params));
126
+ }
127
+ return {
128
+ def,
129
+ handlers: {
130
+ "chat.postMessage": postMessage,
131
+ "chat.update": update,
132
+ call
133
+ }
134
+ };
135
+ }
136
+ function toRecord(r) {
137
+ return { ok: r.ok, status: r.status, body: r.body, error: r.error };
138
+ }
139
+ function slackOutputSchema() {
140
+ return {
141
+ type: "object",
142
+ properties: {
143
+ ok: { type: "boolean", description: "Slack's logical success flag" },
144
+ status: { type: "number", description: "HTTP status" },
145
+ body: { type: "object", description: "Full Slack response payload" },
146
+ error: { type: "string", description: "Slack error code when ok is false" }
147
+ }
148
+ };
149
+ }
150
+
151
+ // src/connector-slack-plugin.ts
152
+ var ConnectorSlackPlugin = class {
153
+ constructor(options) {
154
+ this.name = "com.objectstack.connector.slack";
155
+ this.version = "1.0.0";
156
+ this.type = "standard";
157
+ // Ensure the automation engine (and its connector registry) is started first.
158
+ this.dependencies = ["com.objectstack.service-automation"];
159
+ this.options = options;
160
+ }
161
+ async init(_ctx) {
162
+ }
163
+ async start(ctx) {
164
+ let automation;
165
+ try {
166
+ automation = ctx.getService("automation");
167
+ } catch {
168
+ automation = void 0;
169
+ }
170
+ if (!automation || typeof automation.registerConnector !== "function") {
171
+ ctx.logger.info("ConnectorSlackPlugin: no automation engine \u2014 Slack connector not registered");
172
+ return;
173
+ }
174
+ const { def, handlers } = createSlackConnector(this.options);
175
+ automation.registerConnector(def, handlers);
176
+ this.automation = automation;
177
+ this.connectorName = def.name;
178
+ ctx.logger.info(`ConnectorSlackPlugin: Slack connector '${def.name}' registered`);
179
+ }
180
+ async stop(_ctx) {
181
+ if (this.automation && this.connectorName) {
182
+ try {
183
+ this.automation.unregisterConnector(this.connectorName);
184
+ } catch {
185
+ }
186
+ }
187
+ }
188
+ };
189
+ // Annotate the CommonJS export names for ESM import in node:
190
+ 0 && (module.exports = {
191
+ ConnectorSlackPlugin,
192
+ createSlackConnector
193
+ });
194
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/slack-connector.ts","../src/connector-slack-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/connector-slack\n *\n * Slack Web API connector — a concrete connector (ADR-0018 §Addendum) and the\n * second reference implementation after `@objectstack/connector-rest`. The\n * baseline automation engine ships the `connector_action` dispatch node + an\n * empty connector registry; this plugin populates it with a `slack` connector\n * exposing `chat.postMessage`, `chat.update`, and a generic `call` action.\n *\n * This is the integration mechanism (ADR-0022 \"raw API call\" path), not the\n * human-notification layer. Static bot-token auth only; OAuth2 install/refresh,\n * credential vaulting, and multi-tenant lifecycle are the enterprise tier.\n */\n\nexport {\n createSlackConnector,\n type SlackConnectorOptions,\n type SlackConnectorBundle,\n type SlackPostMessageInput,\n type SlackResult,\n} from './slack-connector.js';\nexport {\n ConnectorSlackPlugin,\n type ConnectorSlackPluginOptions,\n type ConnectorRegistrySurface,\n} from './connector-slack-plugin.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Connector } from '@objectstack/spec/integration';\n\n/**\n * Slack connector — a *concrete* connector (ADR-0018 §Addendum) and the second\n * reference implementation after `@objectstack/connector-rest`. It produces a\n * {@link Connector} definition plus handlers for a small set of Slack Web API\n * actions, which the baseline `connector_action` node dispatches to.\n *\n * Scope (ADR-0022 \"raw API call\" path): this is the *integration mechanism*\n * for talking to Slack's API — \"post this exact text to this channel\". It is\n * deliberately **not** the human-notification layer: there is no preference\n * matrix, inbox, outbox, or thread/session semantics here. Those belong to a\n * `MessagingChannel` (ADR-0012/0013), which may itself delegate its transport\n * to this connector.\n *\n * Open-source scope: **static** auth only — a Slack **bot token** (`xoxb-…`),\n * supplied by the caller and sent as a bearer credential. OAuth2 install/refresh,\n * credential vaulting, and multi-tenant connection lifecycle are the enterprise\n * tier (see `../cloud/docs/design/connector-tiering.md`) and are out of scope.\n *\n * Slack quirk: the Web API returns HTTP `200` even on logical failure, with the\n * real outcome in the JSON body's `ok` field (and `error` on failure). Handlers\n * therefore surface `ok` from the payload, not from the HTTP status, and never\n * throw on a logical failure — the flow author branches on `${node.ok}`.\n */\n\nexport interface SlackConnectorOptions {\n /** Connector machine name (snake_case). Defaults to `slack`. */\n name?: string;\n /** Human-readable label. Defaults to `Slack`. */\n label?: string;\n /** Slack bot token (`xoxb-…`), sent as `Authorization: Bearer <token>`. */\n token: string;\n /** Web API base URL. Defaults to `https://slack.com/api`. */\n baseUrl?: string;\n /** Headers merged into every request (request-level headers win). */\n defaultHeaders?: Record<string, string>;\n /** Injected for tests; defaults to the global `fetch`. */\n fetchImpl?: typeof fetch;\n}\n\n/** Input accepted by `chat.postMessage`. */\nexport interface SlackPostMessageInput {\n /** Channel id (`C…`), user id (`U…`), or channel name (`#general`). */\n channel: string;\n /** Message text (fallback when `blocks` are present). */\n text?: string;\n /** Thread root `ts` to reply into an existing thread. */\n thread_ts?: string;\n /** Block Kit blocks. */\n blocks?: unknown[];\n [key: string]: unknown;\n}\n\n/** Generic Slack Web API result envelope. */\nexport interface SlackResult {\n /** Slack's logical success flag (from the JSON body, not the HTTP status). */\n ok: boolean;\n /** HTTP status (almost always 200 for the Slack Web API). */\n status: number;\n /** Full parsed Slack payload. */\n body: Record<string, unknown>;\n /** Slack error code when `ok` is false (e.g. `channel_not_found`). */\n error?: string;\n}\n\n/** A connector definition paired with its action handlers, ready for registerConnector(). */\nexport interface SlackConnectorBundle {\n def: Connector;\n handlers: Record<\n string,\n (input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>\n >;\n}\n\nexport function createSlackConnector(opts: SlackConnectorOptions): SlackConnectorBundle {\n const name = opts.name ?? 'slack';\n const baseUrl = (opts.baseUrl ?? 'https://slack.com/api').replace(/\\/+$/, '');\n const doFetch = opts.fetchImpl ?? fetch;\n\n const def: Connector = {\n name,\n label: opts.label ?? 'Slack',\n type: 'api',\n description: 'Slack Web API connector (static bot-token auth). Post and update messages, or call any Web API method.',\n icon: 'slack',\n authentication: { type: 'bearer', token: opts.token },\n // Defaulted by ConnectorSchema; set explicitly so the literal satisfies\n // the (post-parse) Connector output type.\n status: 'active',\n enabled: true,\n connectionTimeoutMs: 30000,\n requestTimeoutMs: 30000,\n actions: [\n {\n key: 'chat.postMessage',\n label: 'Post Message',\n description: 'Post a message to a channel, DM, or thread (Slack chat.postMessage).',\n inputSchema: {\n type: 'object',\n required: ['channel'],\n properties: {\n channel: { type: 'string', description: 'Channel id, user id, or #name' },\n text: { type: 'string', description: 'Message text' },\n thread_ts: { type: 'string', description: 'Thread root ts to reply into' },\n blocks: { type: 'array', description: 'Block Kit blocks' },\n },\n },\n outputSchema: slackOutputSchema(),\n },\n {\n key: 'chat.update',\n label: 'Update Message',\n description: 'Edit an existing message (Slack chat.update).',\n inputSchema: {\n type: 'object',\n required: ['channel', 'ts'],\n properties: {\n channel: { type: 'string', description: 'Channel id' },\n ts: { type: 'string', description: 'Timestamp of the message to update' },\n text: { type: 'string', description: 'New message text' },\n blocks: { type: 'array', description: 'New Block Kit blocks' },\n },\n },\n outputSchema: slackOutputSchema(),\n },\n {\n key: 'call',\n label: 'Call Web API Method',\n description: 'Escape hatch — call any Slack Web API method with arbitrary params.',\n inputSchema: {\n type: 'object',\n required: ['method'],\n properties: {\n method: { type: 'string', description: 'Web API method, e.g. conversations.list' },\n params: { type: 'object', description: 'Method parameters (JSON body)' },\n },\n },\n outputSchema: slackOutputSchema(),\n },\n ],\n };\n\n /** POST a JSON body to a Slack Web API method and normalise the result. */\n async function callSlack(method: string, params: Record<string, unknown>): Promise<SlackResult> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json; charset=utf-8',\n ...opts.defaultHeaders,\n Authorization: `Bearer ${opts.token}`,\n };\n\n const response = await doFetch(`${baseUrl}/${method}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(params),\n });\n\n // The Slack Web API always answers with JSON; `ok` is the real outcome.\n const body = (await response.json()) as Record<string, unknown>;\n const ok = body.ok === true;\n return {\n ok,\n status: response.status,\n body,\n error: ok ? undefined : (body.error as string | undefined),\n };\n }\n\n async function postMessage(input: Record<string, unknown>): Promise<Record<string, unknown>> {\n return toRecord(await callSlack('chat.postMessage', input));\n }\n\n async function update(input: Record<string, unknown>): Promise<Record<string, unknown>> {\n return toRecord(await callSlack('chat.update', input));\n }\n\n async function call(input: Record<string, unknown>): Promise<Record<string, unknown>> {\n const method = String(input.method ?? '');\n if (!method) throw new Error(\"slack 'call' action: 'method' is required\");\n const params = (input.params as Record<string, unknown>) ?? {};\n return toRecord(await callSlack(method, params));\n }\n\n return {\n def,\n handlers: {\n 'chat.postMessage': postMessage,\n 'chat.update': update,\n call,\n },\n };\n}\n\nfunction toRecord(r: SlackResult): Record<string, unknown> {\n return { ok: r.ok, status: r.status, body: r.body, error: r.error };\n}\n\nfunction slackOutputSchema(): Record<string, unknown> {\n return {\n type: 'object',\n properties: {\n ok: { type: 'boolean', description: \"Slack's logical success flag\" },\n status: { type: 'number', description: 'HTTP status' },\n body: { type: 'object', description: 'Full Slack response payload' },\n error: { type: 'string', description: 'Slack error code when ok is false' },\n },\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { Connector } from '@objectstack/spec/integration';\nimport { createSlackConnector, type SlackConnectorOptions } from './slack-connector.js';\n\n/**\n * Minimal surface of the automation engine this plugin depends on — the\n * connector registry from ADR-0018 §Addendum. Kept structural so the plugin\n * needs no runtime dependency on `@objectstack/service-automation`.\n */\nexport interface ConnectorRegistrySurface {\n registerConnector(\n def: Connector,\n handlers: Record<\n string,\n (input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>\n >,\n ): void;\n unregisterConnector(name: string): void;\n}\n\nexport interface ConnectorSlackPluginOptions extends SlackConnectorOptions {}\n\n/**\n * ConnectorSlackPlugin — registers a Slack Web API connector on the automation\n * engine. The second reference concrete connector (ADR-0018 §Addendum); it\n * enables the ADR-0022 \"raw API call\" path — a flow's `connector_action` step\n * can dispatch to `slack.chat.postMessage` without the messaging stack.\n *\n * If no automation engine is present the plugin logs and skips — the connector\n * has nowhere to register, which is not an error.\n */\nexport class ConnectorSlackPlugin implements Plugin {\n name = 'com.objectstack.connector.slack';\n version = '1.0.0';\n type = 'standard' as const;\n // Ensure the automation engine (and its connector registry) is started first.\n dependencies = ['com.objectstack.service-automation'];\n\n private readonly options: ConnectorSlackPluginOptions;\n private connectorName?: string;\n private automation?: ConnectorRegistrySurface;\n\n constructor(options: ConnectorSlackPluginOptions) {\n this.options = options;\n }\n\n async init(_ctx: PluginContext): Promise<void> {\n // No services to register; the connector is registered in start() once\n // the automation engine is available.\n }\n\n async start(ctx: PluginContext): Promise<void> {\n let automation: ConnectorRegistrySurface | undefined;\n try {\n automation = ctx.getService<ConnectorRegistrySurface>('automation');\n } catch {\n automation = undefined;\n }\n\n if (!automation || typeof automation.registerConnector !== 'function') {\n ctx.logger.info('ConnectorSlackPlugin: no automation engine — Slack connector not registered');\n return;\n }\n\n const { def, handlers } = createSlackConnector(this.options);\n automation.registerConnector(def, handlers);\n this.automation = automation;\n this.connectorName = def.name;\n ctx.logger.info(`ConnectorSlackPlugin: Slack connector '${def.name}' registered`);\n }\n\n async stop(_ctx: PluginContext): Promise<void> {\n if (this.automation && this.connectorName) {\n try { this.automation.unregisterConnector(this.connectorName); } catch { /* ignore */ }\n }\n }\n}\n"],"mappings":"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","names":[]}