@bakers-build/addon-dropsh 0.0.0-stage → 0.1.0-next.38
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/LICENSE +21 -0
- package/README.md +4 -2
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +148 -0
- package/dist/src/preset.d.ts +2 -0
- package/dist/src/preset.js +8 -0
- package/dist/src/template.d.ts +32 -0
- package/dist/src/template.js +105 -0
- package/dist/src/unpublished-comments.d.ts +12 -0
- package/dist/src/unpublished-comments.js +76 -0
- package/package.json +29 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 keytec GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bakers-build/addon-dropsh
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
bakers.build dropsh command plugin: the `bakers dropsh` JSON:API shell bound to the split connection config.
|
|
4
|
+
|
|
5
|
+
Part of the bakers.build CLI. Install the meta package `@bakers-build/bakers` to get the `bakers` CLI with all addons. Source: https://git.key-tec.de/bakers-build/bakers-build (bakers-cli/).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BbCommandHost, type BbCommandPlugin, type WorkspaceRecoveryOptions } from '@bakers-build/core';
|
|
2
|
+
export declare function dropshConfigHint(resolvedPath?: string): string;
|
|
3
|
+
export interface DropshDispatchOptions extends WorkspaceRecoveryOptions {
|
|
4
|
+
stdout?: (text: string) => void;
|
|
5
|
+
stderr?: (text: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Build the actual plugin registrations after the final connection is ready. */
|
|
8
|
+
export declare function dispatchBbDropsh(host: BbCommandHost, argv: string[], options?: DropshDispatchOptions): Promise<void>;
|
|
9
|
+
declare const dropshCommandPlugin: BbCommandPlugin;
|
|
10
|
+
export default dropshCommandPlugin;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createBbConnectionContext, discoverBbWorkspaces, loadBbConnectionBootstrap, loadReadyBbConnection, } from '@bakers-build/core';
|
|
2
|
+
import { buildProgram as buildDropshProgram } from 'dropsh';
|
|
3
|
+
import { registerTemplateCommand } from './template.js';
|
|
4
|
+
import { hideUnpublishedComments } from './unpublished-comments.js';
|
|
5
|
+
export function dropshConfigHint(resolvedPath) {
|
|
6
|
+
return `bakers dropsh: no connection config at ${resolvedPath ?? '~/.bakers/bakers.config.js'}. Use --config <path> or run bakers config init --scope connection.`;
|
|
7
|
+
}
|
|
8
|
+
/** Consume only wrapper flags; forward all actual dropsh arguments unchanged. */
|
|
9
|
+
function invocation(argv) {
|
|
10
|
+
const forwarded = [];
|
|
11
|
+
let explicit;
|
|
12
|
+
let connection;
|
|
13
|
+
let format;
|
|
14
|
+
let yes = false;
|
|
15
|
+
let profile;
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const token = argv[i];
|
|
18
|
+
if (token === '--yes') {
|
|
19
|
+
yes = true;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (token === '--config' ||
|
|
23
|
+
token === '--connection' ||
|
|
24
|
+
token === '--format' ||
|
|
25
|
+
token === '--auth-profile') {
|
|
26
|
+
const value = argv[i + 1];
|
|
27
|
+
if (value !== undefined) {
|
|
28
|
+
if (token === '--config')
|
|
29
|
+
explicit = value;
|
|
30
|
+
else if (token === '--connection')
|
|
31
|
+
connection = value;
|
|
32
|
+
else if (token === '--format')
|
|
33
|
+
format = value;
|
|
34
|
+
else
|
|
35
|
+
profile = value;
|
|
36
|
+
forwarded.push(token, value);
|
|
37
|
+
i++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (token.startsWith('--config='))
|
|
42
|
+
explicit = token.slice(9);
|
|
43
|
+
if (token.startsWith('--connection='))
|
|
44
|
+
connection = token.slice(13);
|
|
45
|
+
if (token.startsWith('--format='))
|
|
46
|
+
format = token.slice(9);
|
|
47
|
+
forwarded.push(token);
|
|
48
|
+
}
|
|
49
|
+
// Global options can appear late, after the command's positional arguments.
|
|
50
|
+
const positional = forwarded.filter((token, i) => ![
|
|
51
|
+
'--config',
|
|
52
|
+
'--connection',
|
|
53
|
+
'--format',
|
|
54
|
+
'--auth-profile',
|
|
55
|
+
'--view-mode',
|
|
56
|
+
].includes(token) &&
|
|
57
|
+
!/^--(?:config|connection|format|auth-profile|view-mode)=/.test(token) &&
|
|
58
|
+
![
|
|
59
|
+
'--config',
|
|
60
|
+
'--connection',
|
|
61
|
+
'--format',
|
|
62
|
+
'--auth-profile',
|
|
63
|
+
'--view-mode',
|
|
64
|
+
].includes(forwarded[i - 1] ?? ''));
|
|
65
|
+
return { forwarded, explicit, connection, format, yes, profile, positional };
|
|
66
|
+
}
|
|
67
|
+
/** Build the actual plugin registrations after the final connection is ready. */
|
|
68
|
+
export async function dispatchBbDropsh(host, argv, options = {}) {
|
|
69
|
+
const args = invocation(argv);
|
|
70
|
+
const opts = {
|
|
71
|
+
...options,
|
|
72
|
+
...(args.explicit ? { explicit: args.explicit } : {}),
|
|
73
|
+
...(args.connection ? { connection: args.connection } : {}),
|
|
74
|
+
...(args.format ? { format: args.format } : {}),
|
|
75
|
+
yes: options.yes || args.yes,
|
|
76
|
+
};
|
|
77
|
+
const help = argv.includes('--help') || argv.includes('-h') || argv.length === 0;
|
|
78
|
+
const auth = args.positional[0] === 'auth';
|
|
79
|
+
const search = args.positional[0] === 'search' &&
|
|
80
|
+
args.positional[1] === 'bb_workspace' &&
|
|
81
|
+
args.positional.length === 2 &&
|
|
82
|
+
(!args.format || ['md', 'json'].includes(args.format));
|
|
83
|
+
if (search) {
|
|
84
|
+
const connection = await loadBbConnectionBootstrap(host, opts);
|
|
85
|
+
const rows = await discoverBbWorkspaces(connection, opts);
|
|
86
|
+
const stdout = options.stdout ?? ((s) => process.stdout.write(s));
|
|
87
|
+
if (args.format === 'md')
|
|
88
|
+
stdout(`| Workspace | UUID |\n| --- | --- |\n${rows.map((r) => `| ${r.name.replace(/[|\r\n]/g, ' ')} | ${r.id} |`).join('\n')}\n`);
|
|
89
|
+
else
|
|
90
|
+
stdout(`${JSON.stringify(rows, null, 2)}\n`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const connection = help
|
|
94
|
+
? undefined
|
|
95
|
+
: auth
|
|
96
|
+
? await loadBbConnectionBootstrap(host, opts)
|
|
97
|
+
: await loadReadyBbConnection(host, opts);
|
|
98
|
+
const program = buildDropshProgram({
|
|
99
|
+
plugins: connection?.plugins ?? [],
|
|
100
|
+
...(options.stdout ? { stdout: options.stdout } : {}),
|
|
101
|
+
...(options.stderr ? { stderr: options.stderr } : {}),
|
|
102
|
+
...(connection
|
|
103
|
+
? {
|
|
104
|
+
contextFactory: () => createBbConnectionContext(connection, {
|
|
105
|
+
...opts,
|
|
106
|
+
...(args.profile ? { profile: args.profile } : {}),
|
|
107
|
+
wrapHttp: hideUnpublishedComments,
|
|
108
|
+
}),
|
|
109
|
+
}
|
|
110
|
+
: {}),
|
|
111
|
+
});
|
|
112
|
+
if (connection) {
|
|
113
|
+
registerTemplateCommand(program, {
|
|
114
|
+
contextFactory: () => createBbConnectionContext(connection, {
|
|
115
|
+
...opts,
|
|
116
|
+
...(args.profile ? { profile: args.profile } : {}),
|
|
117
|
+
wrapHttp: hideUnpublishedComments,
|
|
118
|
+
}),
|
|
119
|
+
stdout: options.stdout ?? ((s) => process.stdout.write(s)),
|
|
120
|
+
stderr: options.stderr ?? ((s) => process.stderr.write(s)),
|
|
121
|
+
setExitCode: (code) => {
|
|
122
|
+
process.exitCode = code;
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Auth commands perform their own reload; bind it explicitly to the same path.
|
|
127
|
+
const forwarded = connection
|
|
128
|
+
? ['--config', connection.config_path, ...args.forwarded]
|
|
129
|
+
: args.forwarded;
|
|
130
|
+
await program.parseAsync(forwarded, { from: 'user' });
|
|
131
|
+
}
|
|
132
|
+
const dropshCommandPlugin = {
|
|
133
|
+
kind: 'command',
|
|
134
|
+
name: 'dropsh',
|
|
135
|
+
describe: 'JSON:API shell (dropsh) bound to the bakers.build connection config',
|
|
136
|
+
register(program, host) {
|
|
137
|
+
program
|
|
138
|
+
.command('dropsh')
|
|
139
|
+
.description('JSON:API shell bound to the bakers.build connection')
|
|
140
|
+
.helpOption(false)
|
|
141
|
+
.allowUnknownOption()
|
|
142
|
+
.argument('[args...]')
|
|
143
|
+
.action(async (args) => {
|
|
144
|
+
await dispatchBbDropsh(host, args);
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
export default dropshCommandPlugin;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import type { CommandContext } from 'dropsh';
|
|
3
|
+
export interface TemplateRunResult {
|
|
4
|
+
ticket_uuid: string;
|
|
5
|
+
identifier: string | null;
|
|
6
|
+
created: true;
|
|
7
|
+
}
|
|
8
|
+
/** Per-field overrides of the template defaults; relationships by uuid. */
|
|
9
|
+
export interface TemplateOverrides {
|
|
10
|
+
title?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
workflow?: string;
|
|
13
|
+
project_id?: string;
|
|
14
|
+
conductor_id?: string;
|
|
15
|
+
labels?: string[];
|
|
16
|
+
target_state?: string;
|
|
17
|
+
}
|
|
18
|
+
/** The instantiate body: `{}` without overrides, else a ticket document. */
|
|
19
|
+
export declare function overrideDocument(overrides: TemplateOverrides): Record<string, unknown>;
|
|
20
|
+
/**
|
|
21
|
+
* Run a ticket template: exactly one POST. The authenticated client sends
|
|
22
|
+
* writes without transport retries; a failed send stays uncertain here.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runTemplate(client: Pick<CommandContext['client'], 'post'>, uuid: string, overrides?: TemplateOverrides): Promise<TemplateRunResult>;
|
|
25
|
+
export interface TemplateCommandDeps {
|
|
26
|
+
contextFactory: () => Promise<CommandContext>;
|
|
27
|
+
stdout: (text: string) => void;
|
|
28
|
+
stderr: (text: string) => void;
|
|
29
|
+
setExitCode: (code: number) => void;
|
|
30
|
+
}
|
|
31
|
+
/** `bakers dropsh template run <uuid> [--<field> <value>]…`. */
|
|
32
|
+
export declare function registerTemplateCommand(program: Command, deps: TemplateCommandDeps): void;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { HttpError } from 'dropsh/plugin';
|
|
2
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3
|
+
const RELATIONSHIP_TYPES = {
|
|
4
|
+
project_id: 'bb_project--bb_project',
|
|
5
|
+
conductor_id: 'bb_conductor--bb_conductor',
|
|
6
|
+
labels: 'bb_term--bb_labels',
|
|
7
|
+
};
|
|
8
|
+
/** The instantiate body: `{}` without overrides, else a ticket document. */
|
|
9
|
+
export function overrideDocument(overrides) {
|
|
10
|
+
const attributes = {};
|
|
11
|
+
for (const key of ['title', 'description', 'workflow']) {
|
|
12
|
+
if (overrides[key] !== undefined)
|
|
13
|
+
attributes[key] = overrides[key];
|
|
14
|
+
}
|
|
15
|
+
const relationships = {};
|
|
16
|
+
for (const key of ['project_id', 'conductor_id']) {
|
|
17
|
+
const id = overrides[key];
|
|
18
|
+
if (id !== undefined)
|
|
19
|
+
relationships[key] = { data: { type: RELATIONSHIP_TYPES[key], id } };
|
|
20
|
+
}
|
|
21
|
+
if (overrides.labels !== undefined) {
|
|
22
|
+
relationships.labels = {
|
|
23
|
+
data: overrides.labels.map((id) => ({
|
|
24
|
+
type: RELATIONSHIP_TYPES.labels,
|
|
25
|
+
id,
|
|
26
|
+
})),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const data = { type: 'bb_ticket--bb_ticket' };
|
|
30
|
+
if (Object.keys(attributes).length > 0)
|
|
31
|
+
data.attributes = attributes;
|
|
32
|
+
if (Object.keys(relationships).length > 0)
|
|
33
|
+
data.relationships = relationships;
|
|
34
|
+
const document = { data };
|
|
35
|
+
if (overrides.target_state !== undefined)
|
|
36
|
+
document.meta = { target_state: overrides.target_state };
|
|
37
|
+
return Object.keys(data).length > 1 || document.meta ? document : {};
|
|
38
|
+
}
|
|
39
|
+
const REASONS = {
|
|
40
|
+
400: 'The server rejected the request',
|
|
41
|
+
403: 'You are not allowed to run this template',
|
|
42
|
+
404: 'Template not found',
|
|
43
|
+
422: 'The template or its overrides are invalid and cannot produce a ticket',
|
|
44
|
+
};
|
|
45
|
+
function detail(body) {
|
|
46
|
+
const errors = body?.errors;
|
|
47
|
+
const first = errors?.[0]?.detail;
|
|
48
|
+
return typeof first === 'string' ? ` (${first})` : '';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Run a ticket template: exactly one POST. The authenticated client sends
|
|
52
|
+
* writes without transport retries; a failed send stays uncertain here.
|
|
53
|
+
*/
|
|
54
|
+
export async function runTemplate(client, uuid, overrides = {}) {
|
|
55
|
+
if (!UUID.test(uuid)) {
|
|
56
|
+
throw new Error(`template must be a uuid, got "${uuid}"`);
|
|
57
|
+
}
|
|
58
|
+
let document;
|
|
59
|
+
try {
|
|
60
|
+
document = (await client.post(`bb_ticket_template/bb_ticket_template/${uuid}/instantiate`, overrideDocument(overrides)));
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof HttpError) {
|
|
64
|
+
if (error.status === 0) {
|
|
65
|
+
throw new Error('Network failure: the ticket may have been created. Check the project before running the template again.');
|
|
66
|
+
}
|
|
67
|
+
throw new Error(`${REASONS[error.status] ?? `HTTP ${error.status}`}${detail(error.body)}`);
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
const id = document.data?.id;
|
|
72
|
+
if (!id)
|
|
73
|
+
throw new Error('The server answered without a ticket.');
|
|
74
|
+
return {
|
|
75
|
+
ticket_uuid: id,
|
|
76
|
+
identifier: document.data?.attributes?.identifier ?? null,
|
|
77
|
+
created: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** `bakers dropsh template run <uuid> [--<field> <value>]…`. */
|
|
81
|
+
export function registerTemplateCommand(program, deps) {
|
|
82
|
+
program
|
|
83
|
+
.command('template')
|
|
84
|
+
.description('Ticket templates')
|
|
85
|
+
.command('run <uuid>')
|
|
86
|
+
.description('Create a ticket from a template; each flag overrides one template default')
|
|
87
|
+
.option('--project_id <uuid>', 'project to create the ticket in (required for a workspace template)')
|
|
88
|
+
.option('--title <title>', 'ticket title; {{date}} and {{month}} are rendered')
|
|
89
|
+
.option('--description <text>', 'ticket description; {{date}} and {{month}} are rendered')
|
|
90
|
+
.option('--workflow <id>', 'ticket workflow, e.g. bb_feature')
|
|
91
|
+
.option('--labels <uuid...>', 'label uuids, replacing the template labels')
|
|
92
|
+
.option('--conductor_id <uuid>', 'conductor of the ticket project')
|
|
93
|
+
.option('--target_state <id>', 'state the new ticket is moved to')
|
|
94
|
+
.action(async (uuid, overrides) => {
|
|
95
|
+
try {
|
|
96
|
+
const { client } = await deps.contextFactory();
|
|
97
|
+
deps.stdout(`${JSON.stringify(await runTemplate(client, uuid, overrides))}\n`);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
+
deps.stderr(`${JSON.stringify({ error: { message } })}\n`);
|
|
102
|
+
deps.setExitCode(1);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type HttpClient } from 'dropsh/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Agent reads through `bakers dropsh` never see an unpublished comment.
|
|
4
|
+
*
|
|
5
|
+
* Accounts cannot tell an agent from its human, so the server lets the
|
|
6
|
+
* assignee read submitted reviews; the agent-facing shell filters them from
|
|
7
|
+
* GET collections, single reads, includes and the linkages pointing at them.
|
|
8
|
+
* A single read of one fails as dropsh's own client fails a 404.
|
|
9
|
+
* ponytail: keys on `attributes.status`; a sparse fieldset without `status`
|
|
10
|
+
* passes through.
|
|
11
|
+
*/
|
|
12
|
+
export declare function hideUnpublishedComments(http: HttpClient): HttpClient;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { HttpError } from 'dropsh/plugin';
|
|
2
|
+
/** An unpublished bakers.build comment: a review the ticket's assignee has not accepted. */
|
|
3
|
+
function unpublished(resource) {
|
|
4
|
+
return (typeof resource?.type === 'string' &&
|
|
5
|
+
resource.type.startsWith('bb_comment--') &&
|
|
6
|
+
resource.attributes?.status === false);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Agent reads through `bakers dropsh` never see an unpublished comment.
|
|
10
|
+
*
|
|
11
|
+
* Accounts cannot tell an agent from its human, so the server lets the
|
|
12
|
+
* assignee read submitted reviews; the agent-facing shell filters them from
|
|
13
|
+
* GET collections, single reads, includes and the linkages pointing at them.
|
|
14
|
+
* A single read of one fails as dropsh's own client fails a 404.
|
|
15
|
+
* ponytail: keys on `attributes.status`; a sparse fieldset without `status`
|
|
16
|
+
* passes through.
|
|
17
|
+
*/
|
|
18
|
+
export function hideUnpublishedComments(http) {
|
|
19
|
+
return {
|
|
20
|
+
async send(request) {
|
|
21
|
+
const response = await http.send(request);
|
|
22
|
+
return request.method === 'GET' ? filter(response) : response;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function filter(response) {
|
|
27
|
+
let document;
|
|
28
|
+
try {
|
|
29
|
+
document = JSON.parse(response.body);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
if (!document || typeof document !== 'object' || !('data' in document)) {
|
|
35
|
+
return response;
|
|
36
|
+
}
|
|
37
|
+
if (document.data &&
|
|
38
|
+
!Array.isArray(document.data) &&
|
|
39
|
+
unpublished(document.data)) {
|
|
40
|
+
const errors = [
|
|
41
|
+
{
|
|
42
|
+
status: '404',
|
|
43
|
+
title: 'Not Found',
|
|
44
|
+
detail: 'The comment is not published.',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
throw new HttpError(404, 'HTTP 404', { errors });
|
|
48
|
+
}
|
|
49
|
+
const hidden = new Set();
|
|
50
|
+
const keep = (list) => list.filter((resource) => {
|
|
51
|
+
if (!unpublished(resource))
|
|
52
|
+
return true;
|
|
53
|
+
hidden.add(`${resource.type}:${resource.id}`);
|
|
54
|
+
return false;
|
|
55
|
+
});
|
|
56
|
+
if (Array.isArray(document.data))
|
|
57
|
+
document.data = keep(document.data);
|
|
58
|
+
if (Array.isArray(document.included))
|
|
59
|
+
document.included = keep(document.included);
|
|
60
|
+
if (hidden.size === 0)
|
|
61
|
+
return response;
|
|
62
|
+
const primary = Array.isArray(document.data)
|
|
63
|
+
? document.data
|
|
64
|
+
: [document.data];
|
|
65
|
+
for (const resource of [
|
|
66
|
+
...primary,
|
|
67
|
+
...(document.included ?? []),
|
|
68
|
+
]) {
|
|
69
|
+
for (const relationship of Object.values(resource?.relationships ?? {})) {
|
|
70
|
+
if (Array.isArray(relationship?.data)) {
|
|
71
|
+
relationship.data = relationship.data.filter((link) => !hidden.has(`${link.type}:${link.id}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { ...response, body: JSON.stringify(document) };
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bakers-build/addon-dropsh",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-next.38",
|
|
4
|
+
"description": "bakers.build dropsh command plugin: the `bakers dropsh` JSON:API shell bound to the split connection config.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/src/index.js",
|
|
9
|
+
"./preset": "./dist/src/preset.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/src"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://git.key-tec.de/bakers-build/bakers-build.git",
|
|
20
|
+
"directory": "bakers-cli/addons/dropsh"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@dropsh/plugin-jsonapi-schema": "^0.7.1",
|
|
24
|
+
"@dropsh/plugin-oauth2": "^0.7.5",
|
|
25
|
+
"commander": "^12.1.0",
|
|
26
|
+
"dropsh": "^0.7.5"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@bakers-build/core": "^0.1.0-next.38"
|
|
30
|
+
}
|
|
31
|
+
}
|