brickr-sdk 0.1.0

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.
Files changed (3) hide show
  1. package/package.json +18 -0
  2. package/src/index.d.ts +121 -0
  3. package/src/index.js +243 -0
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "brickr-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Brickr SDK for defining code function nodes",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "files": [
8
+ "src"
9
+ ],
10
+ "exports": {
11
+ ".": "./src/index.js"
12
+ },
13
+ "types": "./src/index.d.ts",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "license": "MIT"
18
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,121 @@
1
+ export type PrimitivePinType = 'string' | 'number' | 'boolean' | 'any' | 'sequence';
2
+
3
+ export interface BrickrPin {
4
+ id: string;
5
+ label: string;
6
+ type: string;
7
+ optional?: boolean;
8
+ description?: string;
9
+ defaultValue?: unknown;
10
+ portOnly?: boolean;
11
+ pinOnly?: boolean;
12
+ allowPortOnlyFalse?: boolean;
13
+ allowPinOnlyFalse?: boolean;
14
+ }
15
+
16
+ export interface PinBuilder {
17
+ optional(): PinBuilder;
18
+ description(text: string): PinBuilder;
19
+ default(value: unknown): PinBuilder;
20
+ portOnly(enabled?: boolean): PinBuilder;
21
+ pinOnly(enabled?: boolean): PinBuilder;
22
+ allowInlineValue(enabled?: boolean): PinBuilder;
23
+ }
24
+
25
+ export interface CodeFunctionRunContext<TInputs = Record<string, unknown>> {
26
+ inputs: TInputs;
27
+ request?: {
28
+ method?: string;
29
+ url?: string;
30
+ headers?: Record<string, string>;
31
+ };
32
+ env?: Record<string, unknown>;
33
+ secret(name: string): string;
34
+ log(...args: unknown[]): void;
35
+ fail(message: string, code?: string): never;
36
+ }
37
+
38
+ export interface CodeFunctionNodeDefinition {
39
+ __brickrType: 'code-function-node';
40
+ nodeKey: string;
41
+ name: string;
42
+ description?: string;
43
+ category?: string;
44
+ inputs: BrickrPin[];
45
+ outputs: BrickrPin[];
46
+ run: (ctx: CodeFunctionRunContext) => Promise<Record<string, unknown>> | Record<string, unknown>;
47
+ }
48
+
49
+ export interface EnumDefinition {
50
+ __brickrType: 'enum';
51
+ name: string;
52
+ description?: string;
53
+ values: Array<{ key: string; value: string; label?: string }>;
54
+ }
55
+
56
+ export interface StructureDefinition {
57
+ __brickrType: 'structure';
58
+ name: string;
59
+ description?: string;
60
+ fields: Array<{ name: string; type: string; label?: string; required?: boolean }>;
61
+ }
62
+
63
+ export interface SecretDefinition {
64
+ __brickrType: 'secret';
65
+ name: string;
66
+ description?: string;
67
+ required?: boolean;
68
+ }
69
+
70
+ export declare const t: {
71
+ string(): PinBuilder;
72
+ number(): PinBuilder;
73
+ boolean(): PinBuilder;
74
+ any(): PinBuilder;
75
+ object(name?: string): PinBuilder;
76
+ enumValue(name?: string): PinBuilder;
77
+ struct(name: string): PinBuilder;
78
+ array(inner: PinBuilder): PinBuilder;
79
+ };
80
+
81
+ export declare const seq: {
82
+ in(): PinBuilder;
83
+ out(): PinBuilder;
84
+ };
85
+
86
+ export declare function defineCodeFunctionNode(config: {
87
+ nodeKey: string;
88
+ id?: string;
89
+ name: string;
90
+ description?: string;
91
+ category?: string;
92
+ inputs?: Record<string, PinBuilder | Partial<BrickrPin>>;
93
+ outputs?: Record<string, PinBuilder | Partial<BrickrPin>>;
94
+ run: CodeFunctionNodeDefinition['run'];
95
+ }): CodeFunctionNodeDefinition;
96
+
97
+ export declare function defineEnum(config: {
98
+ name: string;
99
+ description?: string;
100
+ values: Array<string | { key?: string; value?: string; label?: string }>;
101
+ }): EnumDefinition;
102
+
103
+ export declare function defineStructure(config: {
104
+ name: string;
105
+ description?: string;
106
+ fields: Array<{ name: string; type: string; label?: string; required?: boolean }>;
107
+ }): StructureDefinition;
108
+
109
+ export declare function defineSecret(config: {
110
+ name: string;
111
+ description?: string;
112
+ required?: boolean;
113
+ }): SecretDefinition;
114
+
115
+ export declare function buildManifestFromNode(nodeDefinition: CodeFunctionNodeDefinition): Omit<CodeFunctionNodeDefinition, 'run' | '__brickrType'>;
116
+
117
+ export declare function collectAssets(assets: Array<EnumDefinition | StructureDefinition | SecretDefinition>): {
118
+ enums: EnumDefinition[];
119
+ structures: StructureDefinition[];
120
+ secrets: SecretDefinition[];
121
+ };
package/src/index.js ADDED
@@ -0,0 +1,243 @@
1
+ const normalizeString = (value, fallback = '') => {
2
+ if (typeof value === 'string') return value.trim();
3
+ if (value === null || typeof value === 'undefined') return fallback;
4
+ return String(value).trim();
5
+ };
6
+
7
+ const ensureLabel = (value, fallback = '') => {
8
+ const normalized = normalizeString(value, fallback);
9
+ return normalized || fallback;
10
+ };
11
+
12
+ class PinBuilder {
13
+ constructor(type, options = {}) {
14
+ this._type = type;
15
+ this._optional = !!options.optional;
16
+ this._description = options.description || '';
17
+ this._defaultValue = options.defaultValue;
18
+ this._hasDefault = Object.prototype.hasOwnProperty.call(options, 'defaultValue');
19
+ const hasPortOnly = Object.prototype.hasOwnProperty.call(options, 'portOnly');
20
+ const hasPinOnly = Object.prototype.hasOwnProperty.call(options, 'pinOnly');
21
+ this._portOnly = hasPortOnly ? !!options.portOnly : (hasPinOnly ? !!options.pinOnly : false);
22
+ this._allowPortOnlyFalse = Object.prototype.hasOwnProperty.call(options, 'allowPortOnlyFalse')
23
+ ? options.allowPortOnlyFalse
24
+ : options.allowPinOnlyFalse;
25
+ }
26
+
27
+ optional() {
28
+ this._optional = true;
29
+ return this;
30
+ }
31
+
32
+ description(text) {
33
+ this._description = normalizeString(text);
34
+ return this;
35
+ }
36
+
37
+ default(value) {
38
+ this._defaultValue = value;
39
+ this._hasDefault = true;
40
+ return this;
41
+ }
42
+
43
+ portOnly(enabled = true) {
44
+ this._portOnly = !!enabled;
45
+ if (enabled === false) {
46
+ this._allowPortOnlyFalse = true;
47
+ }
48
+ return this;
49
+ }
50
+
51
+ // Alias: many users think in "pinOnly" terms.
52
+ pinOnly(enabled = true) {
53
+ return this.portOnly(enabled);
54
+ }
55
+
56
+ allowInlineValue(enabled = true) {
57
+ if (enabled) {
58
+ this._portOnly = false;
59
+ this._allowPortOnlyFalse = true;
60
+ } else {
61
+ this._portOnly = true;
62
+ }
63
+ return this;
64
+ }
65
+
66
+ toPin(id, label) {
67
+ const pin = {
68
+ id,
69
+ label: ensureLabel(label, id),
70
+ type: this._type,
71
+ optional: this._optional,
72
+ description: this._description || undefined,
73
+ portOnly: !!this._portOnly
74
+ };
75
+
76
+ if (this._allowPortOnlyFalse === false || this._allowPortOnlyFalse === true) {
77
+ pin.allowPortOnlyFalse = this._allowPortOnlyFalse;
78
+ }
79
+
80
+ if (this._hasDefault) {
81
+ pin.defaultValue = this._defaultValue;
82
+ }
83
+
84
+ return pin;
85
+ }
86
+ }
87
+
88
+ const createPinBuilder = (type) => new PinBuilder(type);
89
+
90
+ const normalizePinEntries = (pins = {}) => {
91
+ if (!pins || typeof pins !== 'object') return [];
92
+ return Object.entries(pins).map(([id, builder]) => {
93
+ if (builder instanceof PinBuilder) {
94
+ return builder.toPin(id, id);
95
+ }
96
+
97
+ const fallbackType = normalizeString(builder?.type, 'any') || 'any';
98
+ const hasPortOnly = Object.prototype.hasOwnProperty.call(builder || {}, 'portOnly');
99
+ const hasPinOnly = Object.prototype.hasOwnProperty.call(builder || {}, 'pinOnly');
100
+ const normalizedBuilder = new PinBuilder(fallbackType, {
101
+ optional: !!builder?.optional,
102
+ description: builder?.description || '',
103
+ defaultValue: builder?.defaultValue,
104
+ portOnly: hasPortOnly ? !!builder?.portOnly : (hasPinOnly ? !!builder?.pinOnly : false),
105
+ allowPortOnlyFalse: Object.prototype.hasOwnProperty.call(builder || {}, 'allowPortOnlyFalse')
106
+ ? builder?.allowPortOnlyFalse
107
+ : builder?.allowPinOnlyFalse
108
+ });
109
+ return normalizedBuilder.toPin(id, builder?.label || id);
110
+ });
111
+ };
112
+
113
+ const buildNodeDefinition = (config = {}) => {
114
+ const nodeKey = normalizeString(config.nodeKey || config.id).toLowerCase();
115
+ const name = normalizeString(config.name, nodeKey || 'Code Function');
116
+ if (!nodeKey) {
117
+ throw new Error('defineCodeFunctionNode: "nodeKey" is required');
118
+ }
119
+ if (!config.run || typeof config.run !== 'function') {
120
+ throw new Error('defineCodeFunctionNode: "run" function is required');
121
+ }
122
+
123
+ return {
124
+ __brickrType: 'code-function-node',
125
+ nodeKey,
126
+ name,
127
+ description: normalizeString(config.description),
128
+ category: normalizeString(config.category, 'code-function') || 'code-function',
129
+ inputs: normalizePinEntries(config.inputs),
130
+ outputs: normalizePinEntries(config.outputs),
131
+ run: config.run
132
+ };
133
+ };
134
+
135
+ const sanitizeAssetName = (name) => normalizeString(name);
136
+
137
+ export const defineCodeFunctionNode = (config) => buildNodeDefinition(config);
138
+
139
+ export const defineEnum = (config = {}) => {
140
+ const name = sanitizeAssetName(config.name);
141
+ if (!name) throw new Error('defineEnum: "name" is required');
142
+ const values = Array.isArray(config.values) ? config.values : [];
143
+ return {
144
+ __brickrType: 'enum',
145
+ name,
146
+ description: normalizeString(config.description),
147
+ values: values.map((value) => {
148
+ if (value && typeof value === 'object') {
149
+ const key = normalizeString(value.key || value.value || value.label);
150
+ const normalizedValue = normalizeString(value.value || value.key || key);
151
+ const label = normalizeString(value.label || normalizedValue || key);
152
+ return { key, value: normalizedValue, label };
153
+ }
154
+ const normalized = normalizeString(value);
155
+ return { key: normalized, value: normalized, label: normalized };
156
+ }).filter((entry) => entry.key)
157
+ };
158
+ };
159
+
160
+ export const defineStructure = (config = {}) => {
161
+ const name = sanitizeAssetName(config.name);
162
+ if (!name) throw new Error('defineStructure: "name" is required');
163
+ const fields = Array.isArray(config.fields) ? config.fields : [];
164
+ return {
165
+ __brickrType: 'structure',
166
+ name,
167
+ description: normalizeString(config.description),
168
+ fields: fields.map((field) => ({
169
+ name: sanitizeAssetName(field?.name),
170
+ type: normalizeString(field?.type, 'any') || 'any',
171
+ label: normalizeString(field?.label || field?.name),
172
+ required: !!field?.required
173
+ })).filter((field) => field.name)
174
+ };
175
+ };
176
+
177
+ export const defineSecret = (config = {}) => {
178
+ const name = sanitizeAssetName(config.name);
179
+ if (!name) throw new Error('defineSecret: "name" is required');
180
+ return {
181
+ __brickrType: 'secret',
182
+ name,
183
+ description: normalizeString(config.description),
184
+ required: config.required !== false
185
+ };
186
+ };
187
+
188
+ export const seq = {
189
+ in: () => createPinBuilder('sequence').portOnly(true),
190
+ out: () => createPinBuilder('sequence').portOnly(true)
191
+ };
192
+
193
+ export const t = {
194
+ string: () => createPinBuilder('string'),
195
+ number: () => createPinBuilder('number'),
196
+ boolean: () => createPinBuilder('boolean'),
197
+ any: () => createPinBuilder('any'),
198
+ object: (name = '') => {
199
+ const normalized = normalizeString(name);
200
+ return createPinBuilder(normalized ? `object:${normalized}` : 'object');
201
+ },
202
+ enumValue: (name) => {
203
+ const normalized = normalizeString(name);
204
+ return createPinBuilder(normalized ? `enum-value:${normalized}` : 'enum-value');
205
+ },
206
+ struct: (name) => {
207
+ const normalized = normalizeString(name);
208
+ if (!normalized) {
209
+ throw new Error('t.struct(name): "name" is required');
210
+ }
211
+ return createPinBuilder(`object:${normalized}`);
212
+ },
213
+ array: (innerTypeBuilder) => {
214
+ if (!(innerTypeBuilder instanceof PinBuilder)) {
215
+ throw new Error('t.array(inner): inner must be a Brickr type builder (e.g. t.string())');
216
+ }
217
+ const baseType = normalizeString(innerTypeBuilder._type, 'any') || 'any';
218
+ return createPinBuilder(baseType.endsWith(':array') ? baseType : `${baseType}:array`);
219
+ }
220
+ };
221
+
222
+ export const buildManifestFromNode = (nodeDefinition) => {
223
+ const normalized = buildNodeDefinition(nodeDefinition);
224
+ return {
225
+ nodeKey: normalized.nodeKey,
226
+ name: normalized.name,
227
+ description: normalized.description,
228
+ category: normalized.category,
229
+ inputs: normalized.inputs,
230
+ outputs: normalized.outputs
231
+ };
232
+ };
233
+
234
+ export const collectAssets = (assets = []) => {
235
+ const all = Array.isArray(assets) ? assets : [assets];
236
+ return all.reduce((acc, item) => {
237
+ if (!item || typeof item !== 'object') return acc;
238
+ if (item.__brickrType === 'enum') acc.enums.push(item);
239
+ if (item.__brickrType === 'structure') acc.structures.push(item);
240
+ if (item.__brickrType === 'secret') acc.secrets.push(item);
241
+ return acc;
242
+ }, { enums: [], structures: [], secrets: [] });
243
+ };