@forge/sql 3.0.4 → 3.0.5-experimental-3ed5db1

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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=batch-api.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-api.test.d.ts","sourceRoot":"","sources":["../../src/__test__/batch-api.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const batch_api_1 = require("../batch-api");
4
+ const errors_1 = require("../errors");
5
+ describe('SqlBatchOperation', () => {
6
+ let mockOnExecute;
7
+ beforeEach(() => {
8
+ mockOnExecute = jest.fn();
9
+ });
10
+ it('should initialize with an empty query list if no queries are provided', () => {
11
+ const batchOperation = new batch_api_1.SqlBatchOperation([], mockOnExecute);
12
+ expect(batchOperation['queries']).toEqual([]);
13
+ });
14
+ it('should add a single query to the batch', () => {
15
+ const batchOperation = new batch_api_1.SqlBatchOperation([], mockOnExecute);
16
+ batchOperation.add('SELECT * FROM users');
17
+ expect(batchOperation['queries']).toEqual([{ query: 'SELECT * FROM users', params: undefined }]);
18
+ });
19
+ it('should add multiple queries to the batch', () => {
20
+ const batchOperation = new batch_api_1.SqlBatchOperation([], mockOnExecute);
21
+ batchOperation.add(['SELECT * FROM users', 'SELECT * FROM orders']);
22
+ expect(batchOperation['queries']).toEqual([{ query: 'SELECT * FROM users' }, { query: 'SELECT * FROM orders' }]);
23
+ });
24
+ it('should add a query with parameters to the batch', () => {
25
+ const batchOperation = new batch_api_1.SqlBatchOperation([], mockOnExecute);
26
+ batchOperation.add('SELECT * FROM users WHERE id = ?', [1]);
27
+ expect(batchOperation['queries']).toEqual([{ query: 'SELECT * FROM users WHERE id = ?', params: [1] }]);
28
+ });
29
+ it('should throw an error when executing with no queries', async () => {
30
+ const batchOperation = new batch_api_1.SqlBatchOperation([], mockOnExecute);
31
+ await expect(batchOperation.execute()).rejects.toThrow(errors_1.ForgeSQLError);
32
+ await expect(batchOperation.execute()).rejects.toThrow('No queries to execute in batch');
33
+ });
34
+ it('should call onExecute with the correct queries when executing', async () => {
35
+ const batchOperation = new batch_api_1.SqlBatchOperation([{ query: 'INSERT INTO Users John test@email.com' }], mockOnExecute);
36
+ batchOperation.add('SELECT * FROM users');
37
+ const mockResponse = {
38
+ results: [],
39
+ success: false,
40
+ dbExecutionTime: 0,
41
+ metadata: {}
42
+ };
43
+ mockOnExecute.mockResolvedValueOnce(mockResponse);
44
+ const response = await batchOperation.execute();
45
+ expect(mockOnExecute).toHaveBeenCalledWith([
46
+ { query: 'INSERT INTO Users John test@email.com' },
47
+ { query: 'SELECT * FROM users', params: undefined }
48
+ ]);
49
+ expect(response).toBe(mockResponse);
50
+ });
51
+ });
@@ -4,6 +4,7 @@ const api_1 = require("@forge/api");
4
4
  const sql_1 = require("../sql");
5
5
  const sql_statement_1 = require("../sql-statement");
6
6
  const errors_1 = require("../errors");
7
+ const batch_api_1 = require("../batch-api");
7
8
  jest.mock('@forge/api');
8
9
  describe('SqlClient', () => {
9
10
  let sqlClient;
@@ -23,10 +24,10 @@ describe('SqlClient', () => {
23
24
  describe('storageApi', () => {
24
25
  it('should send a request and return the response body', async () => {
25
26
  mockFetchExecute([]);
26
- const result = await sqlClient['storageApi']('SELECT * FROM test', [], undefined, sql_1.SQL_API_ENDPOINTS.EXECUTE);
27
+ const result = await sqlClient['storageApi']({ query: 'SELECT * FROM test', params: [], method: undefined }, sql_1.SQL_API_ENDPOINTS.EXECUTE);
27
28
  expect(mockFetch).toHaveBeenCalledWith('/api/v1/execute', {
28
29
  method: 'POST',
29
- body: JSON.stringify({ query: 'SELECT * FROM test', params: [], method: 'all' }),
30
+ body: JSON.stringify({ query: 'SELECT * FROM test', params: [] }),
30
31
  redirect: 'follow',
31
32
  headers: { 'Content-Type': 'application/json' }
32
33
  });
@@ -35,7 +36,7 @@ describe('SqlClient', () => {
35
36
  it('should send a request with parameters and method', async () => {
36
37
  mockFetchExecute([]);
37
38
  const params = [1];
38
- const result = await sqlClient['storageApi']('SELECT * FROM test WHERE id = ?', params, 'one', sql_1.SQL_API_ENDPOINTS.EXECUTE);
39
+ const result = await sqlClient['storageApi']({ query: 'SELECT * FROM test WHERE id = ?', params: params, method: 'one' }, sql_1.SQL_API_ENDPOINTS.EXECUTE);
39
40
  expect(mockFetch).toHaveBeenCalledWith('/api/v1/execute', {
40
41
  method: 'POST',
41
42
  body: JSON.stringify({ query: 'SELECT * FROM test WHERE id = ?', params, method: 'one' }),
@@ -46,7 +47,11 @@ describe('SqlClient', () => {
46
47
  });
47
48
  it('should send a request to DDL endpoint with method', async () => {
48
49
  mockFetchExecute([]);
49
- const result = await sqlClient['storageApi']('CREATE TABLE test (id INT)', [], 'one', sql_1.SQL_API_ENDPOINTS.EXECUTE_DDL);
50
+ const result = await sqlClient['storageApi']({
51
+ query: 'CREATE TABLE test (id INT)',
52
+ params: [],
53
+ method: 'one'
54
+ }, sql_1.SQL_API_ENDPOINTS.EXECUTE_DDL);
50
55
  expect(mockFetch).toHaveBeenCalledWith('/api/v1/execute/ddl', {
51
56
  method: 'POST',
52
57
  body: JSON.stringify({ query: 'CREATE TABLE test (id INT)', params: [], method: 'one' }),
@@ -59,7 +64,7 @@ describe('SqlClient', () => {
59
64
  const responseText = 'Invalid JSON';
60
65
  const response = new Response(responseText, { status: 200 });
61
66
  mockFetch.mockResolvedValue(response);
62
- await expect(sqlClient['storageApi']('SELECT * from strange;', [], 'one', sql_1.SQL_API_ENDPOINTS.EXECUTE)).rejects.toThrow(`Unexpected error. Response was not valid JSON: ${responseText}`);
67
+ await expect(sqlClient['storageApi']({ query: 'SELECT * from strange;', params: [], method: 'one' }, sql_1.SQL_API_ENDPOINTS.EXECUTE)).rejects.toThrow(`Unexpected error. Response was not valid JSON: ${responseText}`);
63
68
  });
64
69
  it('should throw ForgeSQLAPIError on API error', async () => {
65
70
  const forgeError = { code: 'INVALID_QUERY', message: 'Invalid SQL query' };
@@ -67,7 +72,7 @@ describe('SqlClient', () => {
67
72
  status: 400
68
73
  });
69
74
  mockFetch.mockResolvedValue(mockResponse);
70
- await expect(sqlClient['storageApi']('INVALID SQL QUERY', [], undefined, sql_1.SQL_API_ENDPOINTS.EXECUTE)).rejects.toThrow(new errors_1.ForgeSQLAPIError({ status: mockResponse.status, statusText: mockResponse.statusText }, forgeError));
75
+ await expect(sqlClient['storageApi']({ query: 'INVALID SQL QUERY', params: [], method: undefined }, sql_1.SQL_API_ENDPOINTS.EXECUTE)).rejects.toThrow(new errors_1.ForgeSQLAPIError({ status: mockResponse.status, statusText: mockResponse.statusText }, forgeError));
71
76
  });
72
77
  });
73
78
  describe('sendRequest', () => {
@@ -170,4 +175,11 @@ describe('SqlClient', () => {
170
175
  await expect(sqlClient.executeDDL('INVALID SQL QUERY')).rejects.toThrow(new errors_1.ForgeSQLAPIError(mockResponse, forgeError));
171
176
  });
172
177
  });
178
+ describe('batch', () => {
179
+ it('should create a SqlBatchOperation instance', () => {
180
+ const mockQuery = { query: 'SELECT * FROM test' };
181
+ const batch = sqlClient.batch([mockQuery]);
182
+ expect(batch).toBeInstanceOf(batch_api_1.SqlBatchOperation);
183
+ });
184
+ });
173
185
  });
@@ -0,0 +1,19 @@
1
+ import { SqlParameters } from './sql-statement';
2
+ import { BatchOperationResponse } from './utils/types';
3
+ export interface BatchQueryBody {
4
+ statements: BatchOperation[];
5
+ }
6
+ export interface BatchOperation {
7
+ query: string;
8
+ params?: SqlParameters;
9
+ }
10
+ export declare class SqlBatchOperation<BatchQueryResults extends any[]> {
11
+ protected queries: BatchOperation[];
12
+ private readonly onExecute;
13
+ constructor(queries: BatchOperation[], onExecute: (queries: BatchOperation[]) => Promise<BatchOperationResponse<BatchQueryResults>>);
14
+ add(query: string, params?: SqlParameters): this;
15
+ add(queries: string[]): this;
16
+ execute(): Promise<BatchOperationResponse<BatchQueryResults>>;
17
+ }
18
+ export { BatchOperationResponse };
19
+ //# sourceMappingURL=batch-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-api.d.ts","sourceRoot":"","sources":["../src/batch-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AACD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,qBAAa,iBAAiB,CAAC,iBAAiB,SAAS,GAAG,EAAE;IAE1D,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADhB,OAAO,EAAE,cAAc,EAAE,EAClB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,OAAO,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;IAO/G,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,IAAI;IAChD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAYtB,OAAO,IAAI,OAAO,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;CAOpE;AACD,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqlBatchOperation = void 0;
4
+ const errors_1 = require("./errors");
5
+ class SqlBatchOperation {
6
+ queries;
7
+ onExecute;
8
+ constructor(queries, onExecute) {
9
+ this.queries = queries;
10
+ this.onExecute = onExecute;
11
+ this.queries = queries;
12
+ }
13
+ add(query, params) {
14
+ if (query instanceof Array) {
15
+ this.queries.push(...query.map((queryOperation) => ({ query: queryOperation })));
16
+ return this;
17
+ }
18
+ this.queries.push({ query, params });
19
+ return this;
20
+ }
21
+ async execute() {
22
+ if (this.queries.length === 0) {
23
+ throw new errors_1.ForgeSQLError('No queries to execute in batch');
24
+ }
25
+ return this.onExecute(this.queries);
26
+ }
27
+ }
28
+ exports.SqlBatchOperation = SqlBatchOperation;
package/out/sql.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { Result } from './utils/types';
2
2
  import { SqlStatement } from './sql-statement';
3
+ import { BatchOperation, SqlBatchOperation } from './batch-api';
3
4
  export declare const SQL_API_ENDPOINTS: {
4
5
  readonly EXECUTE: "/api/v1/execute";
5
6
  readonly EXECUTE_DDL: "/api/v1/execute/ddl";
7
+ readonly EXECUTE_BATCH: "/api/v1/batch";
6
8
  };
7
9
  declare type SqlAPIEndPoints = (typeof SQL_API_ENDPOINTS)[keyof typeof SQL_API_ENDPOINTS];
8
10
  export declare class SqlClient {
@@ -13,6 +15,7 @@ export declare class SqlClient {
13
15
  executeRaw<DataType>(query: string): Promise<Result<DataType>>;
14
16
  _provision(): Promise<void>;
15
17
  executeDDL<DataType>(query: string): Promise<Result<DataType>>;
18
+ batch<BatchQueryResults extends any[]>(batchOperation: BatchOperation[]): SqlBatchOperation<BatchQueryResults>;
16
19
  }
17
20
  export declare const sql: SqlClient;
18
21
  export {};
package/out/sql.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAgC,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI7E,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX,aAAK,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAElF,qBAAa,SAAS;YACN,WAAW;YAYX,UAAU;YAsBV,qBAAqB;IAYnC,OAAO,CAAC,QAAQ,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,eAA2C,GACpD,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAU3B,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAQ9D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;CAGrE;AAED,eAAO,MAAM,GAAG,WAAkB,CAAC"}
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAgC,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG7E,OAAO,EAA0C,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAExG,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAC;AAEX,aAAK,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAElF,qBAAa,SAAS;YACN,WAAW;YAYX,UAAU;YAoBV,qBAAqB;IAenC,OAAO,CAAC,QAAQ,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,eAA2C,GACpD,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAU3B,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAQ9D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IASpE,KAAK,CAAC,iBAAiB,SAAS,GAAG,EAAE,EAAE,cAAc,EAAE,cAAc,EAAE,GAAG,iBAAiB,CAAC,iBAAiB,CAAC;CAQ/G;AAED,eAAO,MAAM,GAAG,WAAkB,CAAC"}
package/out/sql.js CHANGED
@@ -5,9 +5,11 @@ const api_1 = require("@forge/api");
5
5
  const sql_statement_1 = require("./sql-statement");
6
6
  const error_handling_1 = require("./utils/error-handling");
7
7
  const errors_1 = require("./errors");
8
+ const batch_api_1 = require("./batch-api");
8
9
  exports.SQL_API_ENDPOINTS = {
9
10
  EXECUTE: '/api/v1/execute',
10
- EXECUTE_DDL: '/api/v1/execute/ddl'
11
+ EXECUTE_DDL: '/api/v1/execute/ddl',
12
+ EXECUTE_BATCH: '/api/v1/batch'
11
13
  };
12
14
  class SqlClient {
13
15
  async sendRequest(path, options) {
@@ -21,10 +23,10 @@ class SqlClient {
21
23
  });
22
24
  return response;
23
25
  }
24
- async storageApi(query, params = [], method = 'all', endpoint = exports.SQL_API_ENDPOINTS.EXECUTE) {
26
+ async storageApi(body, endpoint = exports.SQL_API_ENDPOINTS.EXECUTE) {
25
27
  const response = await this.sendRequest(endpoint, {
26
28
  method: 'POST',
27
- body: JSON.stringify({ query, params, method })
29
+ body: JSON.stringify(body)
28
30
  });
29
31
  await (0, error_handling_1.checkResponseError)(response);
30
32
  const responseText = await response.text();
@@ -37,7 +39,7 @@ class SqlClient {
37
39
  }
38
40
  async storageApiWithOptions(query, options = {}) {
39
41
  const { endpoint = exports.SQL_API_ENDPOINTS.EXECUTE, params = [], method = 'all' } = options;
40
- return await this.storageApi(query, params, method, endpoint);
42
+ return await this.storageApi({ query, params, method }, endpoint);
41
43
  }
42
44
  prepare(query, endpoint = exports.SQL_API_ENDPOINTS.EXECUTE) {
43
45
  const remoteSqlApi = (query, params, method) => this.storageApiWithOptions(query, { endpoint, params, method });
@@ -52,6 +54,11 @@ class SqlClient {
52
54
  async executeDDL(query) {
53
55
  return await this.prepare(query, exports.SQL_API_ENDPOINTS.EXECUTE_DDL).execute();
54
56
  }
57
+ batch(batchOperation) {
58
+ return new batch_api_1.SqlBatchOperation(batchOperation, (queries) => {
59
+ return this.storageApi({ statements: queries }, exports.SQL_API_ENDPOINTS.EXECUTE_BATCH);
60
+ });
61
+ }
55
62
  }
56
63
  exports.SqlClient = SqlClient;
57
64
  exports.sql = new SqlClient();
@@ -8,6 +8,15 @@ export interface UpdateQueryResponse {
8
8
  serverStatus: number;
9
9
  warningStatus: number;
10
10
  }
11
+ export declare type BatchResults<DataType extends any[]> = {
12
+ [K in keyof DataType]: Result<DataType[K]>;
13
+ };
14
+ export interface BatchOperationResponse<BatchQueryResults extends any[]> {
15
+ success: boolean;
16
+ dbExecutionTime: number;
17
+ results: BatchResults<BatchQueryResults>;
18
+ metadata: Object;
19
+ }
11
20
  export interface Result<DataType = any> {
12
21
  rows: DataType extends UpdateQueryResponse ? UpdateQueryResponse : DataType[];
13
22
  metadata?: Record<string, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,oBAAY,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC,CAAC;AAGnE,MAAM,WAAW,mBAAmB;IAElC,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,MAAM,CAAC;IAEjB,YAAY,EAAE,MAAM,CAAC;IAErB,aAAa,EAAE,MAAM,CAAC;CACvB;AAWD,MAAM,WAAW,MAAM,CAAC,QAAQ,GAAG,GAAG;IAKpC,IAAI,EAAE,QAAQ,SAAS,mBAAmB,GAAG,mBAAmB,GAAG,QAAQ,EAAE,CAAC;IAO9E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,oBAAY,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC,CAAC;AAGnE,MAAM,WAAW,mBAAmB;IAElC,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,MAAM,CAAC;IAEjB,YAAY,EAAE,MAAM,CAAC;IAErB,aAAa,EAAE,MAAM,CAAC;CACvB;AAKD,oBAAY,YAAY,CAAC,QAAQ,SAAS,GAAG,EAAE,IAAI;KAChD,CAAC,IAAI,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;CAC3C,CAAC;AAKF,MAAM,WAAW,sBAAsB,CAAC,iBAAiB,SAAS,GAAG,EAAE;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAWD,MAAM,WAAW,MAAM,CAAC,QAAQ,GAAG,GAAG;IAKpC,IAAI,EAAE,QAAQ,SAAS,mBAAmB,GAAG,mBAAmB,GAAG,QAAQ,EAAE,CAAC;IAO9E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/sql",
3
- "version": "3.0.4",
3
+ "version": "3.0.5-experimental-3ed5db1",
4
4
  "description": "Forge SQL sdk",
5
5
  "author": "Atlassian",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -20,7 +20,7 @@
20
20
  "jest-when": "^3.6.0"
21
21
  },
22
22
  "dependencies": {
23
- "@forge/api": "^6.1.0"
23
+ "@forge/api": "^6.1.1-experimental-3ed5db1"
24
24
  },
25
25
  "publishConfig": {
26
26
  "registry": "https://packages.atlassian.com/api/npm/npm-public/"