@bacano/sdk 1.1.10 → 1.1.13
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/CONTENT_TYPE_MANAGEMENT.md +401 -0
- package/README.md +25 -4
- package/content-management-types.d.ts +260 -0
- package/content-management.cjs +199 -0
- package/content-management.d.ts +14 -0
- package/content-management.js +178 -0
- package/package.json +6 -1
- package/skills/bacano-figma-web/SKILL.md +26 -9
- package/skills/bacano-figma-web/references/bacano-mapping.md +3 -3
- package/skills/bacano-figma-web/references/content-workflow.md +62 -18
- package/skills/bacano-figma-web/references/extraction-contract.md +3 -0
- package/skills/bacano-figma-web/references/implementation-quality.md +67 -0
- package/skills/bacano-figma-web/references/visual-validation.md +4 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
export type ContentManagementTypeKind = "entry" | "component";
|
|
2
|
+
export type ContentManagementTypeStatus = "draft" | "active" | "archived";
|
|
3
|
+
export type ContentManagementTypeUsage = "website_content" | "product_additional" | "product_specification";
|
|
4
|
+
export type ContentManagementScope = "content_types:manage" | "content_entries:manage" | "content_media:upload" | "content_entries:publish";
|
|
5
|
+
export type ContentManagementFieldType = "boolean" | "component" | "date" | "link" | "measure" | "media" | "number" | "reference" | "repeater" | "rich_text" | "rich_text_full" | "select" | "slug" | "text" | "textarea";
|
|
6
|
+
export interface ContentManagementChildFieldInput {
|
|
7
|
+
id?: string | null;
|
|
8
|
+
key: string;
|
|
9
|
+
label: string;
|
|
10
|
+
type: ContentManagementFieldType;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
sortOrder: number;
|
|
13
|
+
settings?: Record<string, unknown>;
|
|
14
|
+
componentKey?: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface ContentManagementFieldInput extends ContentManagementChildFieldInput {
|
|
17
|
+
sectionKey?: string | null;
|
|
18
|
+
children?: ContentManagementChildFieldInput[];
|
|
19
|
+
}
|
|
20
|
+
export interface ContentManagementTypeInput {
|
|
21
|
+
key: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
kind: ContentManagementTypeKind;
|
|
25
|
+
status?: "draft" | "active";
|
|
26
|
+
settings?: Record<string, unknown>;
|
|
27
|
+
usages?: ContentManagementTypeUsage[];
|
|
28
|
+
sections?: Array<{
|
|
29
|
+
key: string;
|
|
30
|
+
title: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
sortOrder: number;
|
|
33
|
+
}>;
|
|
34
|
+
specificationScopes?: Array<{
|
|
35
|
+
category?: string | null;
|
|
36
|
+
subcategoryId?: string | null;
|
|
37
|
+
}>;
|
|
38
|
+
deletedPaths?: string[];
|
|
39
|
+
confirmDestructiveChanges?: boolean;
|
|
40
|
+
fields?: ContentManagementFieldInput[];
|
|
41
|
+
}
|
|
42
|
+
export interface ContentManagementType extends Omit<ContentManagementTypeInput, "status"> {
|
|
43
|
+
id: string;
|
|
44
|
+
companyId: string;
|
|
45
|
+
description: string;
|
|
46
|
+
status: ContentManagementTypeStatus;
|
|
47
|
+
settings: Record<string, unknown>;
|
|
48
|
+
usages: ContentManagementTypeUsage[];
|
|
49
|
+
sections: Array<{
|
|
50
|
+
id: string;
|
|
51
|
+
key: string;
|
|
52
|
+
title: string;
|
|
53
|
+
description: string;
|
|
54
|
+
sortOrder: number;
|
|
55
|
+
}>;
|
|
56
|
+
specificationScopes: Array<{
|
|
57
|
+
id: string;
|
|
58
|
+
category: string | null;
|
|
59
|
+
subcategoryId: string | null;
|
|
60
|
+
}>;
|
|
61
|
+
fields: ContentManagementFieldInput[];
|
|
62
|
+
createdAt: string;
|
|
63
|
+
updatedAt: string;
|
|
64
|
+
}
|
|
65
|
+
export interface ContentManagementContext {
|
|
66
|
+
companyId: string;
|
|
67
|
+
/** @deprecated Use scopes to inspect the complete grant. */
|
|
68
|
+
scope: "content_types:manage";
|
|
69
|
+
scopes: ContentManagementScope[];
|
|
70
|
+
expiresAt: string;
|
|
71
|
+
}
|
|
72
|
+
export type ContentManagementEntryStatus = "draft" | "published" | "archived";
|
|
73
|
+
export interface ContentManagementEntryInput {
|
|
74
|
+
contentType: string;
|
|
75
|
+
key: string;
|
|
76
|
+
name: string;
|
|
77
|
+
locale?: string;
|
|
78
|
+
categoryKey?: string;
|
|
79
|
+
categoryName?: string;
|
|
80
|
+
status?: Exclude<ContentManagementEntryStatus, "archived">;
|
|
81
|
+
tagIds?: string[];
|
|
82
|
+
content?: Record<string, unknown>;
|
|
83
|
+
expectedUpdatedAt?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface ContentManagementEntry {
|
|
86
|
+
id: string;
|
|
87
|
+
companyId: string;
|
|
88
|
+
contentType: {
|
|
89
|
+
id: string;
|
|
90
|
+
key: string;
|
|
91
|
+
name: string;
|
|
92
|
+
};
|
|
93
|
+
key: string;
|
|
94
|
+
name: string;
|
|
95
|
+
locale: string;
|
|
96
|
+
categoryKey: string;
|
|
97
|
+
status: ContentManagementEntryStatus;
|
|
98
|
+
tagIds: string[];
|
|
99
|
+
tags: string[];
|
|
100
|
+
content: Record<string, unknown>;
|
|
101
|
+
publishedAt: string | null;
|
|
102
|
+
createdAt: string;
|
|
103
|
+
updatedAt: string;
|
|
104
|
+
}
|
|
105
|
+
export interface ContentManagementEntryListInput {
|
|
106
|
+
contentType?: string;
|
|
107
|
+
locale?: string;
|
|
108
|
+
status?: ContentManagementEntryStatus;
|
|
109
|
+
limit?: number;
|
|
110
|
+
offset?: number;
|
|
111
|
+
}
|
|
112
|
+
export interface ContentManagementEntryList {
|
|
113
|
+
entries: ContentManagementEntry[];
|
|
114
|
+
total: number;
|
|
115
|
+
}
|
|
116
|
+
export interface ContentManagementReferences {
|
|
117
|
+
categories: Array<{
|
|
118
|
+
code: string;
|
|
119
|
+
name: string;
|
|
120
|
+
subcategories: Array<{
|
|
121
|
+
id: string;
|
|
122
|
+
name: string;
|
|
123
|
+
}>;
|
|
124
|
+
}>;
|
|
125
|
+
optionLists: Array<{
|
|
126
|
+
key: string;
|
|
127
|
+
name: string;
|
|
128
|
+
isExtensible: boolean;
|
|
129
|
+
options: Array<{
|
|
130
|
+
value: string;
|
|
131
|
+
label: string;
|
|
132
|
+
}>;
|
|
133
|
+
}>;
|
|
134
|
+
measureDimensions: Array<{
|
|
135
|
+
code: string;
|
|
136
|
+
name: string;
|
|
137
|
+
canonicalUnitCode: string;
|
|
138
|
+
units: Array<{
|
|
139
|
+
code: string;
|
|
140
|
+
name: string;
|
|
141
|
+
symbol: string;
|
|
142
|
+
}>;
|
|
143
|
+
}>;
|
|
144
|
+
}
|
|
145
|
+
export type ContentManagementGroupStatus = "active" | "inactive";
|
|
146
|
+
export interface ContentManagementGroupInput {
|
|
147
|
+
key: string;
|
|
148
|
+
name: string;
|
|
149
|
+
description?: string;
|
|
150
|
+
sortOrder?: number;
|
|
151
|
+
status?: ContentManagementGroupStatus;
|
|
152
|
+
}
|
|
153
|
+
export interface ContentManagementGroup {
|
|
154
|
+
id: string;
|
|
155
|
+
companyId: string;
|
|
156
|
+
key: string;
|
|
157
|
+
name: string;
|
|
158
|
+
description: string;
|
|
159
|
+
sortOrder: number;
|
|
160
|
+
status: ContentManagementGroupStatus;
|
|
161
|
+
createdAt: string;
|
|
162
|
+
updatedAt: string;
|
|
163
|
+
}
|
|
164
|
+
export type ContentManagementOptionListStatus = "draft" | "active" | "archived";
|
|
165
|
+
export interface ContentManagementOptionListItemInput {
|
|
166
|
+
id?: string | null;
|
|
167
|
+
value: string;
|
|
168
|
+
label: string;
|
|
169
|
+
parentItemId?: string | null;
|
|
170
|
+
sortOrder: number;
|
|
171
|
+
isActive?: boolean;
|
|
172
|
+
metadata?: Record<string, unknown>;
|
|
173
|
+
}
|
|
174
|
+
export interface ContentManagementOptionListInput {
|
|
175
|
+
key: string;
|
|
176
|
+
name: string;
|
|
177
|
+
description?: string;
|
|
178
|
+
status?: Exclude<ContentManagementOptionListStatus, "archived">;
|
|
179
|
+
parentListId?: string | null;
|
|
180
|
+
isExtensible?: boolean;
|
|
181
|
+
confirmDestructiveChanges?: boolean;
|
|
182
|
+
items?: ContentManagementOptionListItemInput[];
|
|
183
|
+
}
|
|
184
|
+
export interface ContentManagementOptionListItem {
|
|
185
|
+
id: string;
|
|
186
|
+
value: string;
|
|
187
|
+
label: string;
|
|
188
|
+
parentItemId: string | null;
|
|
189
|
+
sortOrder: number;
|
|
190
|
+
isActive: boolean;
|
|
191
|
+
metadata: Record<string, unknown>;
|
|
192
|
+
createdAt: string;
|
|
193
|
+
updatedAt: string;
|
|
194
|
+
}
|
|
195
|
+
export interface ContentManagementOptionList {
|
|
196
|
+
id: string;
|
|
197
|
+
companyId: string;
|
|
198
|
+
key: string;
|
|
199
|
+
name: string;
|
|
200
|
+
description: string;
|
|
201
|
+
status: ContentManagementOptionListStatus;
|
|
202
|
+
parentListId: string | null;
|
|
203
|
+
isExtensible: boolean;
|
|
204
|
+
items: ContentManagementOptionListItem[];
|
|
205
|
+
createdAt: string;
|
|
206
|
+
updatedAt: string;
|
|
207
|
+
}
|
|
208
|
+
export type ContentManagementLifecycleOperation = "archive" | "restore" | "delete";
|
|
209
|
+
export interface ContentManagementLifecycleResult {
|
|
210
|
+
success: boolean;
|
|
211
|
+
allowed: boolean;
|
|
212
|
+
applied: boolean;
|
|
213
|
+
entity_id: string | null;
|
|
214
|
+
entity_type: "type" | "component" | "entry" | "group" | "option_list" | null;
|
|
215
|
+
operation: ContentManagementLifecycleOperation | null;
|
|
216
|
+
name: string | null;
|
|
217
|
+
status: string | null;
|
|
218
|
+
dependencies: Array<{
|
|
219
|
+
code: string;
|
|
220
|
+
label: string;
|
|
221
|
+
count: number;
|
|
222
|
+
blocking: boolean;
|
|
223
|
+
}>;
|
|
224
|
+
message: string | null;
|
|
225
|
+
errors: string[];
|
|
226
|
+
}
|
|
227
|
+
export type ContentManagementAccessTokenProvider = () => string | Promise<string>;
|
|
228
|
+
export interface ContentManagementClientConfig {
|
|
229
|
+
apiUrl: string;
|
|
230
|
+
accessToken: string | ContentManagementAccessTokenProvider;
|
|
231
|
+
fetch?: typeof fetch;
|
|
232
|
+
}
|
|
233
|
+
export interface ContentManagementClient {
|
|
234
|
+
getContext(): Promise<ContentManagementContext>;
|
|
235
|
+
getReferences(): Promise<ContentManagementReferences>;
|
|
236
|
+
listTypes(): Promise<ContentManagementType[]>;
|
|
237
|
+
getType(identifier: string): Promise<ContentManagementType>;
|
|
238
|
+
createType(input: ContentManagementTypeInput): Promise<ContentManagementType>;
|
|
239
|
+
updateType(identifier: string, input: ContentManagementTypeInput): Promise<ContentManagementType>;
|
|
240
|
+
inspectLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
241
|
+
applyLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
242
|
+
listEntries(input?: ContentManagementEntryListInput): Promise<ContentManagementEntryList>;
|
|
243
|
+
getEntry(identifier: string, locale?: string): Promise<ContentManagementEntry>;
|
|
244
|
+
createEntry(input: ContentManagementEntryInput): Promise<ContentManagementEntry>;
|
|
245
|
+
updateEntry(identifier: string, input: ContentManagementEntryInput): Promise<ContentManagementEntry>;
|
|
246
|
+
inspectEntryLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
247
|
+
applyEntryLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
248
|
+
listGroups(): Promise<ContentManagementGroup[]>;
|
|
249
|
+
getGroup(identifier: string): Promise<ContentManagementGroup>;
|
|
250
|
+
createGroup(input: ContentManagementGroupInput): Promise<ContentManagementGroup>;
|
|
251
|
+
updateGroup(identifier: string, input: ContentManagementGroupInput): Promise<ContentManagementGroup>;
|
|
252
|
+
inspectGroupLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
253
|
+
applyGroupLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
254
|
+
listOptionLists(): Promise<ContentManagementOptionList[]>;
|
|
255
|
+
getOptionList(identifier: string): Promise<ContentManagementOptionList>;
|
|
256
|
+
createOptionList(input: ContentManagementOptionListInput): Promise<ContentManagementOptionList>;
|
|
257
|
+
updateOptionList(identifier: string, input: ContentManagementOptionListInput): Promise<ContentManagementOptionList>;
|
|
258
|
+
inspectOptionListLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
259
|
+
applyOptionListLifecycle(identifier: string, operation: ContentManagementLifecycleOperation): Promise<ContentManagementLifecycleResult>;
|
|
260
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
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
|
+
// libs/sdk/src/content-management.ts
|
|
21
|
+
var content_management_exports = {};
|
|
22
|
+
__export(content_management_exports, {
|
|
23
|
+
ContentManagementError: () => ContentManagementError,
|
|
24
|
+
createContentManagementClient: () => createContentManagementClient
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(content_management_exports);
|
|
27
|
+
var ContentManagementError = class extends Error {
|
|
28
|
+
code;
|
|
29
|
+
status;
|
|
30
|
+
details;
|
|
31
|
+
constructor(input) {
|
|
32
|
+
super(input.message);
|
|
33
|
+
this.name = "ContentManagementError";
|
|
34
|
+
this.code = input.code ?? "CONTENT_MANAGEMENT_ERROR";
|
|
35
|
+
this.status = input.status;
|
|
36
|
+
this.details = input.details;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
function normalizeApiUrl(apiUrl) {
|
|
40
|
+
const normalized = apiUrl.trim().replace(/\/+$/, "");
|
|
41
|
+
if (!normalized) {
|
|
42
|
+
throw new ContentManagementError({
|
|
43
|
+
message: "apiUrl is required.",
|
|
44
|
+
code: "CONTENT_MANAGEMENT_CONFIG_INVALID",
|
|
45
|
+
status: 0
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return normalized;
|
|
49
|
+
}
|
|
50
|
+
function encodeIdentifier(identifier) {
|
|
51
|
+
const normalized = identifier.trim();
|
|
52
|
+
if (!normalized) {
|
|
53
|
+
throw new ContentManagementError({
|
|
54
|
+
message: "A content type id or key is required.",
|
|
55
|
+
code: "CONTENT_TYPE_IDENTIFIER_INVALID",
|
|
56
|
+
status: 0
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return encodeURIComponent(normalized);
|
|
60
|
+
}
|
|
61
|
+
function entryListPath(input = {}) {
|
|
62
|
+
const search = new URLSearchParams();
|
|
63
|
+
if (input.contentType) search.set("contentType", input.contentType);
|
|
64
|
+
if (input.locale) search.set("locale", input.locale);
|
|
65
|
+
if (input.status) search.set("status", input.status);
|
|
66
|
+
if (input.limit !== void 0) search.set("limit", String(input.limit));
|
|
67
|
+
if (input.offset !== void 0) search.set("offset", String(input.offset));
|
|
68
|
+
const query = search.toString();
|
|
69
|
+
return query ? `/entries?${query}` : "/entries";
|
|
70
|
+
}
|
|
71
|
+
function createContentManagementClient(config) {
|
|
72
|
+
const apiUrl = normalizeApiUrl(config.apiUrl);
|
|
73
|
+
const fetchImplementation = config.fetch ?? globalThis.fetch;
|
|
74
|
+
if (!fetchImplementation) {
|
|
75
|
+
throw new ContentManagementError({
|
|
76
|
+
message: "A fetch implementation is required.",
|
|
77
|
+
code: "CONTENT_MANAGEMENT_CONFIG_INVALID",
|
|
78
|
+
status: 0
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const getAccessToken = async () => {
|
|
82
|
+
const token = typeof config.accessToken === "function" ? await config.accessToken() : config.accessToken;
|
|
83
|
+
const normalized = token.trim();
|
|
84
|
+
if (!normalized) {
|
|
85
|
+
throw new ContentManagementError({
|
|
86
|
+
message: "A temporary content management access token is required.",
|
|
87
|
+
code: "CONTENT_MANAGEMENT_ACCESS_REQUIRED",
|
|
88
|
+
status: 0
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return normalized;
|
|
92
|
+
};
|
|
93
|
+
const request = async (path, init) => {
|
|
94
|
+
const response = await fetchImplementation(
|
|
95
|
+
`${apiUrl}/api/v1/content-management${path}`,
|
|
96
|
+
{
|
|
97
|
+
...init,
|
|
98
|
+
headers: {
|
|
99
|
+
Accept: "application/json",
|
|
100
|
+
Authorization: `Bearer ${await getAccessToken()}`,
|
|
101
|
+
...init?.body ? { "Content-Type": "application/json" } : {},
|
|
102
|
+
...init?.headers
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
let payload = null;
|
|
107
|
+
try {
|
|
108
|
+
payload = await response.json();
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
if (!response.ok || !payload || payload.success !== true) {
|
|
112
|
+
const error = payload && "error" in payload ? payload.error : null;
|
|
113
|
+
throw new ContentManagementError({
|
|
114
|
+
message: error?.message ?? `Content management request failed with HTTP ${response.status}.`,
|
|
115
|
+
code: error?.code,
|
|
116
|
+
status: response.status,
|
|
117
|
+
details: error?.details
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return payload.data;
|
|
121
|
+
};
|
|
122
|
+
const lifecycle = (resource, identifier, operation, dryRun) => request(
|
|
123
|
+
`/${resource}/${encodeIdentifier(identifier)}/lifecycle`,
|
|
124
|
+
{
|
|
125
|
+
method: "POST",
|
|
126
|
+
body: JSON.stringify({ operation, dryRun })
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
return {
|
|
130
|
+
getContext: () => request("/context"),
|
|
131
|
+
getReferences: () => request("/references"),
|
|
132
|
+
listTypes: () => request("/types"),
|
|
133
|
+
getType: (identifier) => request(`/types/${encodeIdentifier(identifier)}`),
|
|
134
|
+
createType: (input) => request("/types", {
|
|
135
|
+
method: "POST",
|
|
136
|
+
body: JSON.stringify(input)
|
|
137
|
+
}),
|
|
138
|
+
updateType: (identifier, input) => request(`/types/${encodeIdentifier(identifier)}`, {
|
|
139
|
+
method: "PUT",
|
|
140
|
+
body: JSON.stringify(input)
|
|
141
|
+
}),
|
|
142
|
+
inspectLifecycle: (identifier, operation) => lifecycle("types", identifier, operation, true),
|
|
143
|
+
applyLifecycle: (identifier, operation) => lifecycle("types", identifier, operation, false),
|
|
144
|
+
listEntries: (input) => request(entryListPath(input)),
|
|
145
|
+
getEntry: (identifier, locale) => {
|
|
146
|
+
const query = locale ? `?locale=${encodeURIComponent(locale.trim())}` : "";
|
|
147
|
+
return request(
|
|
148
|
+
`/entries/${encodeIdentifier(identifier)}${query}`
|
|
149
|
+
);
|
|
150
|
+
},
|
|
151
|
+
createEntry: (input) => request("/entries", {
|
|
152
|
+
method: "POST",
|
|
153
|
+
body: JSON.stringify(input)
|
|
154
|
+
}),
|
|
155
|
+
updateEntry: (identifier, input) => request(
|
|
156
|
+
`/entries/${encodeIdentifier(identifier)}`,
|
|
157
|
+
{
|
|
158
|
+
method: "PUT",
|
|
159
|
+
body: JSON.stringify(input)
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
inspectEntryLifecycle: (identifier, operation) => lifecycle("entries", identifier, operation, true),
|
|
163
|
+
applyEntryLifecycle: (identifier, operation) => lifecycle("entries", identifier, operation, false),
|
|
164
|
+
listGroups: () => request("/groups"),
|
|
165
|
+
getGroup: (identifier) => request(
|
|
166
|
+
`/groups/${encodeIdentifier(identifier)}`
|
|
167
|
+
),
|
|
168
|
+
createGroup: (input) => request("/groups", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body: JSON.stringify(input)
|
|
171
|
+
}),
|
|
172
|
+
updateGroup: (identifier, input) => request(
|
|
173
|
+
`/groups/${encodeIdentifier(identifier)}`,
|
|
174
|
+
{
|
|
175
|
+
method: "PUT",
|
|
176
|
+
body: JSON.stringify(input)
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
inspectGroupLifecycle: (identifier, operation) => lifecycle("groups", identifier, operation, true),
|
|
180
|
+
applyGroupLifecycle: (identifier, operation) => lifecycle("groups", identifier, operation, false),
|
|
181
|
+
listOptionLists: () => request("/option-lists"),
|
|
182
|
+
getOptionList: (identifier) => request(
|
|
183
|
+
`/option-lists/${encodeIdentifier(identifier)}`
|
|
184
|
+
),
|
|
185
|
+
createOptionList: (input) => request("/option-lists", {
|
|
186
|
+
method: "POST",
|
|
187
|
+
body: JSON.stringify(input)
|
|
188
|
+
}),
|
|
189
|
+
updateOptionList: (identifier, input) => request(
|
|
190
|
+
`/option-lists/${encodeIdentifier(identifier)}`,
|
|
191
|
+
{
|
|
192
|
+
method: "PUT",
|
|
193
|
+
body: JSON.stringify(input)
|
|
194
|
+
}
|
|
195
|
+
),
|
|
196
|
+
inspectOptionListLifecycle: (identifier, operation) => lifecycle("option-lists", identifier, operation, true),
|
|
197
|
+
applyOptionListLifecycle: (identifier, operation) => lifecycle("option-lists", identifier, operation, false)
|
|
198
|
+
};
|
|
199
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContentManagementClient, ContentManagementClientConfig } from "./content-management-types";
|
|
2
|
+
export * from "./content-management-types";
|
|
3
|
+
export declare class ContentManagementError extends Error {
|
|
4
|
+
readonly code: string;
|
|
5
|
+
readonly status: number;
|
|
6
|
+
readonly details: unknown;
|
|
7
|
+
constructor(input: {
|
|
8
|
+
message: string;
|
|
9
|
+
code?: string;
|
|
10
|
+
status: number;
|
|
11
|
+
details?: unknown;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export declare function createContentManagementClient(config: ContentManagementClientConfig): ContentManagementClient;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// libs/sdk/src/content-management.ts
|
|
2
|
+
var ContentManagementError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
status;
|
|
5
|
+
details;
|
|
6
|
+
constructor(input) {
|
|
7
|
+
super(input.message);
|
|
8
|
+
this.name = "ContentManagementError";
|
|
9
|
+
this.code = input.code ?? "CONTENT_MANAGEMENT_ERROR";
|
|
10
|
+
this.status = input.status;
|
|
11
|
+
this.details = input.details;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function normalizeApiUrl(apiUrl) {
|
|
15
|
+
const normalized = apiUrl.trim().replace(/\/+$/, "");
|
|
16
|
+
if (!normalized) {
|
|
17
|
+
throw new ContentManagementError({
|
|
18
|
+
message: "apiUrl is required.",
|
|
19
|
+
code: "CONTENT_MANAGEMENT_CONFIG_INVALID",
|
|
20
|
+
status: 0
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
function encodeIdentifier(identifier) {
|
|
26
|
+
const normalized = identifier.trim();
|
|
27
|
+
if (!normalized) {
|
|
28
|
+
throw new ContentManagementError({
|
|
29
|
+
message: "A content type id or key is required.",
|
|
30
|
+
code: "CONTENT_TYPE_IDENTIFIER_INVALID",
|
|
31
|
+
status: 0
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return encodeURIComponent(normalized);
|
|
35
|
+
}
|
|
36
|
+
function entryListPath(input = {}) {
|
|
37
|
+
const search = new URLSearchParams();
|
|
38
|
+
if (input.contentType) search.set("contentType", input.contentType);
|
|
39
|
+
if (input.locale) search.set("locale", input.locale);
|
|
40
|
+
if (input.status) search.set("status", input.status);
|
|
41
|
+
if (input.limit !== void 0) search.set("limit", String(input.limit));
|
|
42
|
+
if (input.offset !== void 0) search.set("offset", String(input.offset));
|
|
43
|
+
const query = search.toString();
|
|
44
|
+
return query ? `/entries?${query}` : "/entries";
|
|
45
|
+
}
|
|
46
|
+
function createContentManagementClient(config) {
|
|
47
|
+
const apiUrl = normalizeApiUrl(config.apiUrl);
|
|
48
|
+
const fetchImplementation = config.fetch ?? globalThis.fetch;
|
|
49
|
+
if (!fetchImplementation) {
|
|
50
|
+
throw new ContentManagementError({
|
|
51
|
+
message: "A fetch implementation is required.",
|
|
52
|
+
code: "CONTENT_MANAGEMENT_CONFIG_INVALID",
|
|
53
|
+
status: 0
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const getAccessToken = async () => {
|
|
57
|
+
const token = typeof config.accessToken === "function" ? await config.accessToken() : config.accessToken;
|
|
58
|
+
const normalized = token.trim();
|
|
59
|
+
if (!normalized) {
|
|
60
|
+
throw new ContentManagementError({
|
|
61
|
+
message: "A temporary content management access token is required.",
|
|
62
|
+
code: "CONTENT_MANAGEMENT_ACCESS_REQUIRED",
|
|
63
|
+
status: 0
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return normalized;
|
|
67
|
+
};
|
|
68
|
+
const request = async (path, init) => {
|
|
69
|
+
const response = await fetchImplementation(
|
|
70
|
+
`${apiUrl}/api/v1/content-management${path}`,
|
|
71
|
+
{
|
|
72
|
+
...init,
|
|
73
|
+
headers: {
|
|
74
|
+
Accept: "application/json",
|
|
75
|
+
Authorization: `Bearer ${await getAccessToken()}`,
|
|
76
|
+
...init?.body ? { "Content-Type": "application/json" } : {},
|
|
77
|
+
...init?.headers
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
let payload = null;
|
|
82
|
+
try {
|
|
83
|
+
payload = await response.json();
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
if (!response.ok || !payload || payload.success !== true) {
|
|
87
|
+
const error = payload && "error" in payload ? payload.error : null;
|
|
88
|
+
throw new ContentManagementError({
|
|
89
|
+
message: error?.message ?? `Content management request failed with HTTP ${response.status}.`,
|
|
90
|
+
code: error?.code,
|
|
91
|
+
status: response.status,
|
|
92
|
+
details: error?.details
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return payload.data;
|
|
96
|
+
};
|
|
97
|
+
const lifecycle = (resource, identifier, operation, dryRun) => request(
|
|
98
|
+
`/${resource}/${encodeIdentifier(identifier)}/lifecycle`,
|
|
99
|
+
{
|
|
100
|
+
method: "POST",
|
|
101
|
+
body: JSON.stringify({ operation, dryRun })
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
return {
|
|
105
|
+
getContext: () => request("/context"),
|
|
106
|
+
getReferences: () => request("/references"),
|
|
107
|
+
listTypes: () => request("/types"),
|
|
108
|
+
getType: (identifier) => request(`/types/${encodeIdentifier(identifier)}`),
|
|
109
|
+
createType: (input) => request("/types", {
|
|
110
|
+
method: "POST",
|
|
111
|
+
body: JSON.stringify(input)
|
|
112
|
+
}),
|
|
113
|
+
updateType: (identifier, input) => request(`/types/${encodeIdentifier(identifier)}`, {
|
|
114
|
+
method: "PUT",
|
|
115
|
+
body: JSON.stringify(input)
|
|
116
|
+
}),
|
|
117
|
+
inspectLifecycle: (identifier, operation) => lifecycle("types", identifier, operation, true),
|
|
118
|
+
applyLifecycle: (identifier, operation) => lifecycle("types", identifier, operation, false),
|
|
119
|
+
listEntries: (input) => request(entryListPath(input)),
|
|
120
|
+
getEntry: (identifier, locale) => {
|
|
121
|
+
const query = locale ? `?locale=${encodeURIComponent(locale.trim())}` : "";
|
|
122
|
+
return request(
|
|
123
|
+
`/entries/${encodeIdentifier(identifier)}${query}`
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
createEntry: (input) => request("/entries", {
|
|
127
|
+
method: "POST",
|
|
128
|
+
body: JSON.stringify(input)
|
|
129
|
+
}),
|
|
130
|
+
updateEntry: (identifier, input) => request(
|
|
131
|
+
`/entries/${encodeIdentifier(identifier)}`,
|
|
132
|
+
{
|
|
133
|
+
method: "PUT",
|
|
134
|
+
body: JSON.stringify(input)
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
inspectEntryLifecycle: (identifier, operation) => lifecycle("entries", identifier, operation, true),
|
|
138
|
+
applyEntryLifecycle: (identifier, operation) => lifecycle("entries", identifier, operation, false),
|
|
139
|
+
listGroups: () => request("/groups"),
|
|
140
|
+
getGroup: (identifier) => request(
|
|
141
|
+
`/groups/${encodeIdentifier(identifier)}`
|
|
142
|
+
),
|
|
143
|
+
createGroup: (input) => request("/groups", {
|
|
144
|
+
method: "POST",
|
|
145
|
+
body: JSON.stringify(input)
|
|
146
|
+
}),
|
|
147
|
+
updateGroup: (identifier, input) => request(
|
|
148
|
+
`/groups/${encodeIdentifier(identifier)}`,
|
|
149
|
+
{
|
|
150
|
+
method: "PUT",
|
|
151
|
+
body: JSON.stringify(input)
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
inspectGroupLifecycle: (identifier, operation) => lifecycle("groups", identifier, operation, true),
|
|
155
|
+
applyGroupLifecycle: (identifier, operation) => lifecycle("groups", identifier, operation, false),
|
|
156
|
+
listOptionLists: () => request("/option-lists"),
|
|
157
|
+
getOptionList: (identifier) => request(
|
|
158
|
+
`/option-lists/${encodeIdentifier(identifier)}`
|
|
159
|
+
),
|
|
160
|
+
createOptionList: (input) => request("/option-lists", {
|
|
161
|
+
method: "POST",
|
|
162
|
+
body: JSON.stringify(input)
|
|
163
|
+
}),
|
|
164
|
+
updateOptionList: (identifier, input) => request(
|
|
165
|
+
`/option-lists/${encodeIdentifier(identifier)}`,
|
|
166
|
+
{
|
|
167
|
+
method: "PUT",
|
|
168
|
+
body: JSON.stringify(input)
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
inspectOptionListLifecycle: (identifier, operation) => lifecycle("option-lists", identifier, operation, true),
|
|
172
|
+
applyOptionListLifecycle: (identifier, operation) => lifecycle("option-lists", identifier, operation, false)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
ContentManagementError,
|
|
177
|
+
createContentManagementClient
|
|
178
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bacano/sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "TypeScript SDK for building websites on the Bacano ERP",
|
|
5
5
|
"main": "./index.cjs",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"import": "./graphql.js",
|
|
24
24
|
"require": "./graphql.cjs"
|
|
25
25
|
},
|
|
26
|
+
"./content-management": {
|
|
27
|
+
"types": "./content-management.d.ts",
|
|
28
|
+
"import": "./content-management.js",
|
|
29
|
+
"require": "./content-management.cjs"
|
|
30
|
+
},
|
|
26
31
|
"./react": {
|
|
27
32
|
"types": "./react.d.ts",
|
|
28
33
|
"import": "./react.js",
|