forge-fsql 1.0.2 → 1.0.4
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/README.md +20 -28
- package/bin/setup +75 -39
- package/dist/cjs/cli.d.ts +1 -0
- package/dist/cjs/client.d.ts +16 -0
- package/dist/cjs/client.js +1 -5
- package/dist/cjs/commands.d.ts +12 -0
- package/dist/cjs/execute-sql.d.ts +12 -0
- package/dist/cjs/formatter.d.ts +9 -0
- package/dist/cjs/history.d.ts +10 -0
- package/dist/cjs/index.d.ts +18 -0
- package/dist/cli.d.ts +1 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.js +0 -1
- package/dist/commands.d.ts +12 -0
- package/dist/execute-sql.d.ts +12 -0
- package/dist/formatter.d.ts +9 -0
- package/dist/history.d.ts +10 -0
- package/dist/index.d.ts +18 -0
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -15,8 +15,17 @@ Interactive command-line interface for querying Atlassian Forge SQL databases vi
|
|
|
15
15
|
|
|
16
16
|
### In Your Forge Project
|
|
17
17
|
|
|
18
|
-
```
|
|
19
|
-
|
|
18
|
+
```sh
|
|
19
|
+
npm install -D forge-fsql
|
|
20
|
+
|
|
21
|
+
# add webtrigger to manifest.yml and a wrapper module for the corresponding function
|
|
22
|
+
node_modules/.bin/fsql-setup
|
|
23
|
+
|
|
24
|
+
# deploy with the webtrigger
|
|
25
|
+
forge deploy
|
|
26
|
+
|
|
27
|
+
# get trigger url:
|
|
28
|
+
forge webtrigger create --product Confluence --site <site>.atlassian.net --functionKey execute-sql
|
|
20
29
|
```
|
|
21
30
|
|
|
22
31
|
Add to your `package.json` scripts:
|
|
@@ -24,37 +33,20 @@ Add to your `package.json` scripts:
|
|
|
24
33
|
```json
|
|
25
34
|
{
|
|
26
35
|
"scripts": {
|
|
27
|
-
"
|
|
36
|
+
"fsql": "fsql"
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
pnpm add -g forge-fsql
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Configuration
|
|
39
|
-
|
|
40
|
-
Create a `.env` file in your project root:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
FORGE_SQL_URL=https://your-trigger-url.forge.atlassian.com/sql
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Or pass via command line:
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
fsql --url https://your-trigger-url.com
|
|
50
|
-
```
|
|
41
|
+
## Run
|
|
51
42
|
|
|
52
|
-
|
|
43
|
+
```sh
|
|
44
|
+
# set URL using value from previous step
|
|
45
|
+
export FORGE_SQL_URL=https://your-trigger-url.com
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
pnpm sql
|
|
47
|
+
# run fsql!
|
|
48
|
+
npm run fsql
|
|
57
49
|
|
|
58
|
-
#
|
|
59
|
-
fsql
|
|
50
|
+
# or
|
|
51
|
+
npm run fsql --url https://your-trigger-url.com
|
|
60
52
|
```
|
package/bin/setup
CHANGED
|
@@ -6,7 +6,7 @@ import { createRequire } from "module";
|
|
|
6
6
|
|
|
7
7
|
// Support both ESM and CJS imports for js-yaml
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
9
|
-
const
|
|
9
|
+
const YAML = require("yaml");
|
|
10
10
|
|
|
11
11
|
const projectRoot = process.cwd();
|
|
12
12
|
|
|
@@ -67,45 +67,70 @@ if (!fs.existsSync(manifestPath)) {
|
|
|
67
67
|
process.exit(1);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
let
|
|
70
|
+
let doc;
|
|
71
71
|
try {
|
|
72
72
|
const fileContents = fs.readFileSync(manifestPath, "utf8");
|
|
73
|
-
|
|
73
|
+
doc = YAML.parseDocument(fileContents);
|
|
74
74
|
} catch (e) {
|
|
75
75
|
console.error("Error reading manifest:", e);
|
|
76
76
|
process.exit(1);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (!
|
|
80
|
-
|
|
79
|
+
if (!doc.contents) {
|
|
80
|
+
doc.contents = doc.createNode({});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
if (!doc.has("modules")) {
|
|
84
|
+
doc.set("modules", doc.createNode({}));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const modules = doc.get("modules");
|
|
88
|
+
|
|
83
89
|
// Ensure function is an array
|
|
84
90
|
const functionKey = "executeSql";
|
|
85
|
-
if (!
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
if (!modules.has("function")) {
|
|
92
|
+
modules.set("function", doc.createNode([]));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let functions = modules.get("function");
|
|
96
|
+
|
|
97
|
+
// If it's somehow not a sequence, convert it (though unlikely in Forge)
|
|
98
|
+
if (!YAML.isSeq(functions)) {
|
|
99
|
+
const obj = functions.toJSON();
|
|
100
|
+
functions = doc.createNode(
|
|
101
|
+
Object.entries(obj).map(([key, val]) => ({ key, ...val })),
|
|
91
102
|
);
|
|
103
|
+
modules.set("function", functions);
|
|
92
104
|
}
|
|
93
105
|
|
|
94
|
-
const functionExists = manifest.modules.function.find(
|
|
95
|
-
(f) => f.key === functionKey,
|
|
96
|
-
);
|
|
97
106
|
const handlerName = "fsql.executeSql";
|
|
107
|
+
let functionExists = functions.items.find((f) => {
|
|
108
|
+
const js = f.toJSON();
|
|
109
|
+
return js && js.key === functionKey;
|
|
110
|
+
});
|
|
98
111
|
|
|
99
112
|
if (!functionExists) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
113
|
+
functions.add(
|
|
114
|
+
doc.createNode({
|
|
115
|
+
key: functionKey,
|
|
116
|
+
handler: handlerName,
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
104
119
|
console.log(
|
|
105
120
|
`✓ Added function:${functionKey} with handler ${handlerName} to manifest`,
|
|
106
121
|
);
|
|
107
122
|
} else {
|
|
108
|
-
|
|
123
|
+
// If it's a Pair (map item) or just a Map in the sequence
|
|
124
|
+
if (YAML.isMap(functionExists)) {
|
|
125
|
+
functionExists.set("handler", handlerName);
|
|
126
|
+
} else {
|
|
127
|
+
// Should not happen with doc.createNode above, but for safety:
|
|
128
|
+
const idx = functions.items.indexOf(functionExists);
|
|
129
|
+
functions.set(
|
|
130
|
+
idx,
|
|
131
|
+
doc.createNode({ key: functionKey, handler: handlerName }),
|
|
132
|
+
);
|
|
133
|
+
}
|
|
109
134
|
console.log(
|
|
110
135
|
`✓ Updated function:${functionKey} handler to ${handlerName} in manifest`,
|
|
111
136
|
);
|
|
@@ -113,38 +138,49 @@ if (!functionExists) {
|
|
|
113
138
|
|
|
114
139
|
// Ensure webtrigger is an array
|
|
115
140
|
const webtriggerKey = "execute-sql";
|
|
116
|
-
if (!
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
141
|
+
if (!modules.has("webtrigger")) {
|
|
142
|
+
modules.set("webtrigger", doc.createNode([]));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let webtriggers = modules.get("webtrigger");
|
|
146
|
+
if (!YAML.isSeq(webtriggers)) {
|
|
147
|
+
const obj = webtriggers.toJSON();
|
|
148
|
+
webtriggers = doc.createNode(
|
|
149
|
+
Object.entries(obj).map(([key, val]) => ({ key, ...val })),
|
|
121
150
|
);
|
|
151
|
+
modules.set("webtrigger", webtriggers);
|
|
122
152
|
}
|
|
123
153
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
let webtriggerExists = webtriggers.items.find((w) => {
|
|
155
|
+
const js = w.toJSON();
|
|
156
|
+
return js && js.key === webtriggerKey;
|
|
157
|
+
});
|
|
158
|
+
|
|
127
159
|
if (!webtriggerExists) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
160
|
+
webtriggers.add(
|
|
161
|
+
doc.createNode({
|
|
162
|
+
key: webtriggerKey,
|
|
163
|
+
function: functionKey,
|
|
164
|
+
}),
|
|
165
|
+
);
|
|
132
166
|
console.log(`✓ Added webtrigger:${webtriggerKey} to manifest`);
|
|
133
167
|
} else {
|
|
134
|
-
webtriggerExists
|
|
168
|
+
if (YAML.isMap(webtriggerExists)) {
|
|
169
|
+
webtriggerExists.set("function", functionKey);
|
|
170
|
+
} else {
|
|
171
|
+
const idx = webtriggers.items.indexOf(webtriggerExists);
|
|
172
|
+
webtriggers.set(
|
|
173
|
+
idx,
|
|
174
|
+
doc.createNode({ key: webtriggerKey, function: functionKey }),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
135
177
|
console.log(
|
|
136
178
|
`✓ Ensured webtrigger:${webtriggerKey} points to function ${functionKey}`,
|
|
137
179
|
);
|
|
138
180
|
}
|
|
139
181
|
|
|
140
182
|
try {
|
|
141
|
-
|
|
142
|
-
const newYaml = yaml.dump(manifest, {
|
|
143
|
-
indent: 2,
|
|
144
|
-
lineWidth: -1,
|
|
145
|
-
noRefs: true,
|
|
146
|
-
});
|
|
147
|
-
fs.writeFileSync(manifestPath, newYaml);
|
|
183
|
+
fs.writeFileSync(manifestPath, doc.toString());
|
|
148
184
|
console.log("✓ Updated manifest file successfully");
|
|
149
185
|
} catch (e) {
|
|
150
186
|
console.error("Error writing manifest:", e);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SqlResult {
|
|
2
|
+
rows?: any[];
|
|
3
|
+
affectedRows?: number;
|
|
4
|
+
error?: string;
|
|
5
|
+
metadata?: Record<string, any>;
|
|
6
|
+
}
|
|
7
|
+
export interface ClientConfig {
|
|
8
|
+
url: string;
|
|
9
|
+
timeout?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class ForgeClient {
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config: ClientConfig);
|
|
14
|
+
execute(sql: string): Promise<SqlResult>;
|
|
15
|
+
testConnection(): Promise<boolean>;
|
|
16
|
+
}
|
package/dist/cjs/client.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.ForgeClient = void 0;
|
|
7
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
8
4
|
class ForgeClient {
|
|
9
5
|
constructor(config) {
|
|
10
6
|
this.config = {
|
|
@@ -22,7 +18,7 @@ class ForgeClient {
|
|
|
22
18
|
const headers = {
|
|
23
19
|
"Content-Type": "application/json",
|
|
24
20
|
};
|
|
25
|
-
const response = await (
|
|
21
|
+
const response = await fetch(this.config.url, {
|
|
26
22
|
method: "POST",
|
|
27
23
|
headers,
|
|
28
24
|
body: JSON.stringify({ query: finalSql }),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ForgeClient } from "./client.js";
|
|
2
|
+
export interface Command {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
execute: (client: ForgeClient, args?: string) => Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
export declare const specialCommands: Command[];
|
|
8
|
+
export declare function parseCommand(input: string): {
|
|
9
|
+
command?: Command;
|
|
10
|
+
args?: string;
|
|
11
|
+
isSpecial: boolean;
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const executeSql: (req: {
|
|
2
|
+
body: string;
|
|
3
|
+
}) => Promise<ReturnType<typeof getHttpResponse>>;
|
|
4
|
+
declare function getHttpResponse(statusCode: number, body: Record<string, unknown>): {
|
|
5
|
+
headers: {
|
|
6
|
+
"Content-Type": string[];
|
|
7
|
+
};
|
|
8
|
+
statusCode: number;
|
|
9
|
+
statusText: string;
|
|
10
|
+
body: string;
|
|
11
|
+
};
|
|
12
|
+
export { executeSql };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SqlResult } from "./client.js";
|
|
2
|
+
export declare class ResultFormatter {
|
|
3
|
+
static formatTable(rows: any[]): string;
|
|
4
|
+
static formatValue(value: any): string;
|
|
5
|
+
static formatError(error: string): string;
|
|
6
|
+
static formatSuccess(message: string): string;
|
|
7
|
+
static formatResult(result: SqlResult): string;
|
|
8
|
+
static formatQueryTime(ms: number): string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { ForgeClient } from "./client.js";
|
|
2
|
+
export { executeSql } from "./execute-sql.js";
|
|
3
|
+
interface CliConfig {
|
|
4
|
+
url?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ForgeSqlCli {
|
|
7
|
+
private client;
|
|
8
|
+
private rl;
|
|
9
|
+
private history;
|
|
10
|
+
private multilineBuffer;
|
|
11
|
+
private isMultiline;
|
|
12
|
+
constructor(config: CliConfig);
|
|
13
|
+
private setupHandlers;
|
|
14
|
+
private handleLine;
|
|
15
|
+
private executeCommand;
|
|
16
|
+
private handleClose;
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SqlResult {
|
|
2
|
+
rows?: any[];
|
|
3
|
+
affectedRows?: number;
|
|
4
|
+
error?: string;
|
|
5
|
+
metadata?: Record<string, any>;
|
|
6
|
+
}
|
|
7
|
+
export interface ClientConfig {
|
|
8
|
+
url: string;
|
|
9
|
+
timeout?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class ForgeClient {
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config: ClientConfig);
|
|
14
|
+
execute(sql: string): Promise<SqlResult>;
|
|
15
|
+
testConnection(): Promise<boolean>;
|
|
16
|
+
}
|
package/dist/client.js
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ForgeClient } from "./client.js";
|
|
2
|
+
export interface Command {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
execute: (client: ForgeClient, args?: string) => Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
export declare const specialCommands: Command[];
|
|
8
|
+
export declare function parseCommand(input: string): {
|
|
9
|
+
command?: Command;
|
|
10
|
+
args?: string;
|
|
11
|
+
isSpecial: boolean;
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const executeSql: (req: {
|
|
2
|
+
body: string;
|
|
3
|
+
}) => Promise<ReturnType<typeof getHttpResponse>>;
|
|
4
|
+
declare function getHttpResponse(statusCode: number, body: Record<string, unknown>): {
|
|
5
|
+
headers: {
|
|
6
|
+
"Content-Type": string[];
|
|
7
|
+
};
|
|
8
|
+
statusCode: number;
|
|
9
|
+
statusText: string;
|
|
10
|
+
body: string;
|
|
11
|
+
};
|
|
12
|
+
export { executeSql };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SqlResult } from "./client.js";
|
|
2
|
+
export declare class ResultFormatter {
|
|
3
|
+
static formatTable(rows: any[]): string;
|
|
4
|
+
static formatValue(value: any): string;
|
|
5
|
+
static formatError(error: string): string;
|
|
6
|
+
static formatSuccess(message: string): string;
|
|
7
|
+
static formatResult(result: SqlResult): string;
|
|
8
|
+
static formatQueryTime(ms: number): string;
|
|
9
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { ForgeClient } from "./client.js";
|
|
2
|
+
export { executeSql } from "./execute-sql.js";
|
|
3
|
+
interface CliConfig {
|
|
4
|
+
url?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ForgeSqlCli {
|
|
7
|
+
private client;
|
|
8
|
+
private rl;
|
|
9
|
+
private history;
|
|
10
|
+
private multilineBuffer;
|
|
11
|
+
private isMultiline;
|
|
12
|
+
constructor(config: CliConfig);
|
|
13
|
+
private setupHandlers;
|
|
14
|
+
private handleLine;
|
|
15
|
+
private executeCommand;
|
|
16
|
+
private handleClose;
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-fsql",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive SQL CLI for Atlassian Forge SQL via web triggers",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -12,9 +12,14 @@
|
|
|
12
12
|
},
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"import":
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
"import": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/cjs/index.d.ts",
|
|
21
|
+
"default": "./dist/cjs/index.js"
|
|
22
|
+
}
|
|
18
23
|
}
|
|
19
24
|
},
|
|
20
25
|
"files": [
|
|
@@ -41,12 +46,11 @@
|
|
|
41
46
|
"chalk": "^5.4.1",
|
|
42
47
|
"cli-table3": "^0.6.3",
|
|
43
48
|
"dotenv": "^16.0.3",
|
|
44
|
-
"
|
|
49
|
+
"yaml": "^2.8.2"
|
|
45
50
|
},
|
|
46
51
|
"devDependencies": {
|
|
47
52
|
"@eslint/eslintrc": "^3.3.3",
|
|
48
53
|
"@eslint/js": "^9.39.1",
|
|
49
|
-
"@types/js-yaml": "^4.0.9",
|
|
50
54
|
"@types/node": "^22.19.1",
|
|
51
55
|
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
|
52
56
|
"@typescript-eslint/parser": "^8.48.0",
|