@bakers-build/addon-workspace 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 +82 -0
- package/dist/src/index.js +208 -0
- package/dist/src/preset.d.ts +3 -0
- package/dist/src/preset.js +8 -0
- package/package.json +26 -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-workspace
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
bakers.build connection addon: fills the ambient workspace (bb_workspace) into a create payload transparently, via dropsh's alterRequest hook.
|
|
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,82 @@
|
|
|
1
|
+
import type { DropSHPlugin } from 'dropsh/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* The entity types whose workspace is a DIRECT `workspace_id` field, and which
|
|
4
|
+
* this addon may therefore fill from context.
|
|
5
|
+
*
|
|
6
|
+
* `bb_project` and `bb_ticket` are deliberately ABSENT. Their workspace
|
|
7
|
+
* anchor is `group_id` / `project_id` — a genuine choice the caller must make
|
|
8
|
+
* (which group? which project?), not an ambient fact. The server narrows the
|
|
9
|
+
* offer for those two (`GroupInActiveWorkspaceSelection` /
|
|
10
|
+
* `ProjectInActiveWorkspaceSelection`) and `BbWorkspaceScope` gates the write;
|
|
11
|
+
* guessing one here would be inventing data, not supplying context.
|
|
12
|
+
*
|
|
13
|
+
* `bb_term` joined in BB-339. It meets the criterion exactly — a direct
|
|
14
|
+
* `workspace_id`, and which workspace a label belongs to is ambient rather than
|
|
15
|
+
* chosen — and it is not merely a convenience: `@bakers-build/qualify-ticket` creates a
|
|
16
|
+
* missing `work:*` term through dropsh, so without this entry that step answers
|
|
17
|
+
* 422 on `workspace_id` on every instance where the term is not seeded yet.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DEFAULT_WORKSPACE_ENTITY_TYPES: readonly string[];
|
|
20
|
+
/**
|
|
21
|
+
* Entity type → the JSON:API field path from it to the `bb_workspace` uuid.
|
|
22
|
+
*
|
|
23
|
+
* This is a SECOND list beside DEFAULT_WORKSPACE_ENTITY_TYPES and not an
|
|
24
|
+
* extension of it, because the two answer different questions. That one asks
|
|
25
|
+
* "is the workspace an ambient fact on a create?" and excludes bb_project and
|
|
26
|
+
* bb_ticket precisely because choosing their group/project is the caller's
|
|
27
|
+
* decision. This one asks "how is this type reachable from a workspace?", and
|
|
28
|
+
* for those two the answer exists — it is just longer.
|
|
29
|
+
*
|
|
30
|
+
* `bb_workspace` itself is deliberately ABSENT (BB-472 live verification):
|
|
31
|
+
* a `bb_workspace` collection search is exactly how `discoverBbWorkspaces()`
|
|
32
|
+
* lists what an identity can switch to, and narrowing it to
|
|
33
|
+
* `id = <the already-configured workspace>` would make every reachable
|
|
34
|
+
* workspace but the current one invisible — defeating the switch this ticket
|
|
35
|
+
* builds. Server-side membership (F2) already bounds that collection to what
|
|
36
|
+
* the identity may see; this client-side layer answers "which one is
|
|
37
|
+
* configured for creates/other reads", a question that does not apply to the
|
|
38
|
+
* workspace list itself.
|
|
39
|
+
*/
|
|
40
|
+
export declare const WORKSPACE_READ_SCOPE_PATHS: Readonly<Record<string, string | readonly string[]>>;
|
|
41
|
+
/**
|
|
42
|
+
* BB-495 D5: every UI collection read that is NOT workspace-scoped by
|
|
43
|
+
* {@link WORKSPACE_READ_SCOPE_PATHS} and is, deliberately, not a gap to close
|
|
44
|
+
* here — closing one would be its own behaviour change and its own scope. The
|
|
45
|
+
* completeness gate (`addons/bakers-ui/tests/workspace-scope-coverage.test.ts`)
|
|
46
|
+
* derives every collection the UI reads from its source tree and fails on any
|
|
47
|
+
* that is neither covered above nor named here, so a new unscoped read is
|
|
48
|
+
* caught rather than silently added to an ever-growing exception list.
|
|
49
|
+
*/
|
|
50
|
+
export declare const UI_COLLECTION_EXCEPTIONS: readonly string[];
|
|
51
|
+
/** Options for the workspace addon — normally the connection config's globals. */
|
|
52
|
+
export interface WorkspaceOptions {
|
|
53
|
+
/**
|
|
54
|
+
* The UUID of the `bb_workspace` every create is bound to. REQUIRED at the
|
|
55
|
+
* top level of the connection config; `loadBbConfig` rejects a config
|
|
56
|
+
* without it, so by the time this addon runs the value is present.
|
|
57
|
+
*/
|
|
58
|
+
workspace_id?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Override the entity types whose `workspace_id` is filled from context.
|
|
61
|
+
* Defaults to `DEFAULT_WORKSPACE_ENTITY_TYPES`; configurable so a site that
|
|
62
|
+
* adds a further directly-bound type does not need a new addon release.
|
|
63
|
+
*/
|
|
64
|
+
entity_types?: string[];
|
|
65
|
+
}
|
|
66
|
+
/** No workspace configured, but a create needed one. Named so `PluginError` reads. */
|
|
67
|
+
export declare class WorkspaceConfigError extends Error {
|
|
68
|
+
readonly name = "WorkspaceConfigError";
|
|
69
|
+
}
|
|
70
|
+
/** The create body was not parseable JSON — fail loudly, never half-parse. */
|
|
71
|
+
export declare class WorkspacePayloadError extends Error {
|
|
72
|
+
readonly name = "WorkspacePayloadError";
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The bakers.build workspace plugin. Constructed by the `./preset` accumulator from the
|
|
76
|
+
* connection config's global options (via `@bakers-build/addon-essentials`, which
|
|
77
|
+
* lists this addon as a preset child), or directly by dropsh from a legacy
|
|
78
|
+
* `plugins: []` descriptor (this module default-exports the factory, so no
|
|
79
|
+
* `export:` is needed either way).
|
|
80
|
+
*/
|
|
81
|
+
export declare function workspacePlugin(opts?: WorkspaceOptions): DropSHPlugin;
|
|
82
|
+
export default workspacePlugin;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entity types whose workspace is a DIRECT `workspace_id` field, and which
|
|
3
|
+
* this addon may therefore fill from context.
|
|
4
|
+
*
|
|
5
|
+
* `bb_project` and `bb_ticket` are deliberately ABSENT. Their workspace
|
|
6
|
+
* anchor is `group_id` / `project_id` — a genuine choice the caller must make
|
|
7
|
+
* (which group? which project?), not an ambient fact. The server narrows the
|
|
8
|
+
* offer for those two (`GroupInActiveWorkspaceSelection` /
|
|
9
|
+
* `ProjectInActiveWorkspaceSelection`) and `BbWorkspaceScope` gates the write;
|
|
10
|
+
* guessing one here would be inventing data, not supplying context.
|
|
11
|
+
*
|
|
12
|
+
* `bb_term` joined in BB-339. It meets the criterion exactly — a direct
|
|
13
|
+
* `workspace_id`, and which workspace a label belongs to is ambient rather than
|
|
14
|
+
* chosen — and it is not merely a convenience: `@bakers-build/qualify-ticket` creates a
|
|
15
|
+
* missing `work:*` term through dropsh, so without this entry that step answers
|
|
16
|
+
* 422 on `workspace_id` on every instance where the term is not seeded yet.
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_WORKSPACE_ENTITY_TYPES = [
|
|
19
|
+
'bb_group',
|
|
20
|
+
'bb_team',
|
|
21
|
+
'bb_term',
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Entity type → the JSON:API field path from it to the `bb_workspace` uuid.
|
|
25
|
+
*
|
|
26
|
+
* This is a SECOND list beside DEFAULT_WORKSPACE_ENTITY_TYPES and not an
|
|
27
|
+
* extension of it, because the two answer different questions. That one asks
|
|
28
|
+
* "is the workspace an ambient fact on a create?" and excludes bb_project and
|
|
29
|
+
* bb_ticket precisely because choosing their group/project is the caller's
|
|
30
|
+
* decision. This one asks "how is this type reachable from a workspace?", and
|
|
31
|
+
* for those two the answer exists — it is just longer.
|
|
32
|
+
*
|
|
33
|
+
* `bb_workspace` itself is deliberately ABSENT (BB-472 live verification):
|
|
34
|
+
* a `bb_workspace` collection search is exactly how `discoverBbWorkspaces()`
|
|
35
|
+
* lists what an identity can switch to, and narrowing it to
|
|
36
|
+
* `id = <the already-configured workspace>` would make every reachable
|
|
37
|
+
* workspace but the current one invisible — defeating the switch this ticket
|
|
38
|
+
* builds. Server-side membership (F2) already bounds that collection to what
|
|
39
|
+
* the identity may see; this client-side layer answers "which one is
|
|
40
|
+
* configured for creates/other reads", a question that does not apply to the
|
|
41
|
+
* workspace list itself.
|
|
42
|
+
*/
|
|
43
|
+
export const WORKSPACE_READ_SCOPE_PATHS = {
|
|
44
|
+
bb_group: 'workspace_id.id',
|
|
45
|
+
bb_team: 'workspace_id.id',
|
|
46
|
+
// bb_machine is account-owned: it has no workspace_id, and
|
|
47
|
+
// machineCapacity() must not send one. Isolation is owner_user_id on the
|
|
48
|
+
// server, not this client filter.
|
|
49
|
+
bb_term: 'workspace_id.id',
|
|
50
|
+
bb_project: 'group_id.workspace_id.id',
|
|
51
|
+
bb_ticket: 'project_id.group_id.workspace_id.id',
|
|
52
|
+
bb_environment: 'project_id.group_id.workspace_id.id',
|
|
53
|
+
bb_conductor: 'project_id.group_id.workspace_id.id',
|
|
54
|
+
// Exactly one of project and workspace is set on a template: either path
|
|
55
|
+
// admits it (an OR group).
|
|
56
|
+
bb_ticket_template: [
|
|
57
|
+
'project_id.group_id.workspace_id.id',
|
|
58
|
+
'workspace_id.id',
|
|
59
|
+
],
|
|
60
|
+
bb_run: 'ticket_id.project_id.group_id.workspace_id.id',
|
|
61
|
+
bb_comment: 'ticket_id.project_id.group_id.workspace_id.id',
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* BB-495 D5: every UI collection read that is NOT workspace-scoped by
|
|
65
|
+
* {@link WORKSPACE_READ_SCOPE_PATHS} and is, deliberately, not a gap to close
|
|
66
|
+
* here — closing one would be its own behaviour change and its own scope. The
|
|
67
|
+
* completeness gate (`addons/bakers-ui/tests/workspace-scope-coverage.test.ts`)
|
|
68
|
+
* derives every collection the UI reads from its source tree and fails on any
|
|
69
|
+
* that is neither covered above nor named here, so a new unscoped read is
|
|
70
|
+
* caught rather than silently added to an ever-growing exception list.
|
|
71
|
+
*/
|
|
72
|
+
export const UI_COLLECTION_EXCEPTIONS = [
|
|
73
|
+
// `user` is not a bakers.build entity type — `WorkspaceReadScopeSubscriber`
|
|
74
|
+
// registers nothing for it (it hangs off `entity.query_access.<type>` for
|
|
75
|
+
// bakers.build types only), so `WORKSPACE_READ_SCOPE_PATHS` cannot list it either.
|
|
76
|
+
'user',
|
|
77
|
+
// A bespoke resource, not an entity query — `Entity/user/Data/users.ts:41`
|
|
78
|
+
// already called it "unscoped statistics" before this gate existed.
|
|
79
|
+
'bakers/statistics',
|
|
80
|
+
// OG core's own membership resource, not a bakers.build entity type either — the
|
|
81
|
+
// same class of gap as `user`, for the same subscriber-registration reason.
|
|
82
|
+
'og_membership',
|
|
83
|
+
// Deliberately never scoped, not merely unregistered: `bb_workspace`
|
|
84
|
+
// itself IS the reachable-workspace list — narrowing it to the already-
|
|
85
|
+
// configured workspace would make every workspace but the current one
|
|
86
|
+
// invisible, defeating the picker/switch this collection exists for.
|
|
87
|
+
// Server-side membership already bounds it to what the identity may see.
|
|
88
|
+
'bb_workspace',
|
|
89
|
+
// A bespoke resource keyed by ONE ticket's UUID, gated on view access to that
|
|
90
|
+
// ticket — the ticket already sits in the workspace it belongs to, so there
|
|
91
|
+
// is no collection to narrow.
|
|
92
|
+
'bakers/addons/ticket',
|
|
93
|
+
];
|
|
94
|
+
/** The filter group name. Unique by construction, so a caller filter cannot collide. */
|
|
95
|
+
const READ_SCOPE_FILTER = 'bb_ambient_workspace';
|
|
96
|
+
/** The JSON:API resource type of the workspace a `workspace_id` names. */
|
|
97
|
+
const WORKSPACE_RESOURCE_TYPE = 'bb_workspace--bb_workspace';
|
|
98
|
+
/** The relationship this addon fills. */
|
|
99
|
+
const WORKSPACE_FIELD = 'workspace_id';
|
|
100
|
+
/** No workspace configured, but a create needed one. Named so `PluginError` reads. */
|
|
101
|
+
export class WorkspaceConfigError extends Error {
|
|
102
|
+
name = 'WorkspaceConfigError';
|
|
103
|
+
}
|
|
104
|
+
/** The create body was not parseable JSON — fail loudly, never half-parse. */
|
|
105
|
+
export class WorkspacePayloadError extends Error {
|
|
106
|
+
name = 'WorkspacePayloadError';
|
|
107
|
+
}
|
|
108
|
+
function isRecord(v) {
|
|
109
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The bakers.build workspace plugin. Constructed by the `./preset` accumulator from the
|
|
113
|
+
* connection config's global options (via `@bakers-build/addon-essentials`, which
|
|
114
|
+
* lists this addon as a preset child), or directly by dropsh from a legacy
|
|
115
|
+
* `plugins: []` descriptor (this module default-exports the factory, so no
|
|
116
|
+
* `export:` is needed either way).
|
|
117
|
+
*/
|
|
118
|
+
export function workspacePlugin(opts = {}) {
|
|
119
|
+
const workspaceId = typeof opts.workspace_id === 'string' ? opts.workspace_id.trim() : '';
|
|
120
|
+
const entityTypes = new Set(opts.entity_types ?? [...DEFAULT_WORKSPACE_ENTITY_TYPES]);
|
|
121
|
+
return {
|
|
122
|
+
id: 'bakers-workspace',
|
|
123
|
+
requiredModules: [],
|
|
124
|
+
async alterRequest(req, ctx) {
|
|
125
|
+
// Reads: narrow a COLLECTION to the configured workspace. `read` (an
|
|
126
|
+
// individual resource by uuid) is deliberately absent — JSON:API ignores
|
|
127
|
+
// filters on individual endpoints, so appending one there would be code that
|
|
128
|
+
// lies about what it does. Isolation on that path stays the server's.
|
|
129
|
+
if (ctx.operation === 'search') {
|
|
130
|
+
const path = ctx.entityType
|
|
131
|
+
? WORKSPACE_READ_SCOPE_PATHS[ctx.entityType]
|
|
132
|
+
: undefined;
|
|
133
|
+
if (workspaceId === '' || path === undefined)
|
|
134
|
+
return req;
|
|
135
|
+
const url = new URL(req.url);
|
|
136
|
+
const condition = (name, conditionPath) => {
|
|
137
|
+
url.searchParams.set(`filter[${name}][condition][path]`, conditionPath);
|
|
138
|
+
url.searchParams.set(`filter[${name}][condition][operator]`, '=');
|
|
139
|
+
url.searchParams.set(`filter[${name}][condition][value]`, workspaceId);
|
|
140
|
+
};
|
|
141
|
+
if (typeof path === 'string') {
|
|
142
|
+
condition(READ_SCOPE_FILTER, path);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
url.searchParams.set(`filter[${READ_SCOPE_FILTER}][group][conjunction]`, 'OR');
|
|
146
|
+
path.forEach((alternative, i) => {
|
|
147
|
+
condition(`${READ_SCOPE_FILTER}_${i}`, alternative);
|
|
148
|
+
url.searchParams.set(`filter[${READ_SCOPE_FILTER}_${i}][condition][memberOf]`, READ_SCOPE_FILTER);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return { ...req, url: url.toString() };
|
|
152
|
+
}
|
|
153
|
+
// (1) Creates only. An `update` that re-binds an existing row to another
|
|
154
|
+
// workspace is a real decision governed by the server's own rule — never
|
|
155
|
+
// something to slip in ambiently — so PATCH is passed through untouched.
|
|
156
|
+
if (ctx.operation !== 'create')
|
|
157
|
+
return req;
|
|
158
|
+
// (2) Only the types whose workspace is a direct `workspace_id` field.
|
|
159
|
+
if (ctx.entityType === undefined || !entityTypes.has(ctx.entityType)) {
|
|
160
|
+
return req;
|
|
161
|
+
}
|
|
162
|
+
// (3) `upload` bodies are binary; nothing to parse.
|
|
163
|
+
if (typeof req.body !== 'string')
|
|
164
|
+
return req;
|
|
165
|
+
// (6) A create that needs a workspace with none configured must not go out
|
|
166
|
+
// unbound — the server would answer 422 and the cause would be invisible.
|
|
167
|
+
// dropsh wraps this in a PluginError carrying `bakers-workspace`. Normally
|
|
168
|
+
// unreachable: `workspace_id` is required at config load.
|
|
169
|
+
if (workspaceId === '') {
|
|
170
|
+
throw new WorkspaceConfigError(`@bakers-build/addon-workspace: creating a "${ctx.entityType}" needs an ambient workspace, but none is configured. ` +
|
|
171
|
+
`Set the top-level \`${WORKSPACE_FIELD}: '<bb_workspace uuid>'\` in your connection config (.bakers/bakers.config.js).`);
|
|
172
|
+
}
|
|
173
|
+
// (7) Malformed JSON must fail by name, never be swallowed into a request
|
|
174
|
+
// that is half-rewritten.
|
|
175
|
+
let doc;
|
|
176
|
+
try {
|
|
177
|
+
doc = JSON.parse(req.body);
|
|
178
|
+
}
|
|
179
|
+
catch (cause) {
|
|
180
|
+
throw new WorkspacePayloadError(`@bakers-build/addon-workspace: the "${ctx.entityType}" create body is not valid JSON, so the ambient workspace could not be applied: ${String(cause)}`);
|
|
181
|
+
}
|
|
182
|
+
if (!isRecord(doc) || !isRecord(doc.data))
|
|
183
|
+
return req;
|
|
184
|
+
const relationships = isRecord(doc.data.relationships)
|
|
185
|
+
? doc.data.relationships
|
|
186
|
+
: undefined;
|
|
187
|
+
// (4) An explicit value ALWAYS wins over the ambient one.
|
|
188
|
+
if (relationships && WORKSPACE_FIELD in relationships)
|
|
189
|
+
return req;
|
|
190
|
+
// (5) Inject. Headers are untouched by construction — only `body` is
|
|
191
|
+
// replaced, so `Authorization` (applied before this hook) survives verbatim.
|
|
192
|
+
const next = {
|
|
193
|
+
...doc,
|
|
194
|
+
data: {
|
|
195
|
+
...doc.data,
|
|
196
|
+
relationships: {
|
|
197
|
+
...(relationships ?? {}),
|
|
198
|
+
[WORKSPACE_FIELD]: {
|
|
199
|
+
data: { type: WORKSPACE_RESOURCE_TYPE, id: workspaceId },
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
return { ...req, body: JSON.stringify(next) };
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
export default workspacePlugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bakers-build/addon-workspace",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-next.38",
|
|
4
|
+
"description": "bakers.build connection addon: fills the ambient workspace (bb_workspace) into a create payload transparently, via dropsh's alterRequest hook.",
|
|
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/workspace"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"dropsh": "^0.7.5"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@bakers-build/core": "^0.1.0-next.38"
|
|
27
|
+
}
|
|
28
|
+
}
|