@openserv-labs/client 1.0.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.
@@ -0,0 +1,142 @@
1
+ import type { PlatformClient } from "./client";
2
+ import type { WorkflowConfig, TriggerDefinition, TaskDefinition, EdgeDefinition, Edge } from "./types";
3
+ import { Workflow } from "./workflow";
4
+ /**
5
+ * API for managing workflows on the OpenServ platform.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const client = new PlatformClient({ apiKey: 'your-key' });
10
+ *
11
+ * // Create a workflow
12
+ * const workflow = await client.workflows.create({
13
+ * name: 'My Workflow',
14
+ * goal: 'Process data automatically',
15
+ * agentIds: [123, 456]
16
+ * });
17
+ *
18
+ * // List all workflows
19
+ * const workflows = await client.workflows.list();
20
+ *
21
+ * // Get a specific workflow
22
+ * const workflow = await client.workflows.get({ id: 789 });
23
+ * ```
24
+ */
25
+ export declare class WorkflowsAPI {
26
+ private client;
27
+ constructor(client: PlatformClient);
28
+ /**
29
+ * Create a new workflow.
30
+ *
31
+ * Can create an empty workflow or a fully configured one with triggers, tasks, and edges.
32
+ *
33
+ * @param config - Workflow configuration
34
+ * @param config.name - Name of the workflow
35
+ * @param config.goal - Goal/description of what the workflow does
36
+ * @param config.agentIds - Array of agent IDs to include in the workflow
37
+ * @param config.triggers - Optional array of trigger definitions
38
+ * @param config.tasks - Optional array of task definitions
39
+ * @param config.edges - Optional array of edge definitions connecting nodes
40
+ * @returns The created Workflow object
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Simple workflow
45
+ * const workflow = await client.workflows.create({
46
+ * name: 'Data Pipeline',
47
+ * goal: 'Process incoming data',
48
+ * agentIds: [123]
49
+ * });
50
+ *
51
+ * // Workflow with tasks
52
+ * const workflow = await client.workflows.create({
53
+ * name: 'Data Pipeline',
54
+ * goal: 'Process incoming data',
55
+ * agentIds: [123],
56
+ * tasks: [{ name: 'process', agentId: 123, description: 'Process data' }]
57
+ * });
58
+ * ```
59
+ */
60
+ create(config: WorkflowConfig): Promise<Workflow>;
61
+ /**
62
+ * Get a workflow by ID.
63
+ * @param params - Parameters object
64
+ * @param params.id - The workflow ID
65
+ * @returns The Workflow object with full data including triggers, tasks, and edges
66
+ */
67
+ get(params: {
68
+ id: number | string;
69
+ }): Promise<Workflow>;
70
+ /**
71
+ * List all workflows owned by the authenticated user.
72
+ * @returns Array of Workflow objects
73
+ */
74
+ list(): Promise<Workflow[]>;
75
+ /**
76
+ * Update workflow metadata.
77
+ * @param params - Parameters object
78
+ * @param params.id - The workflow ID to update
79
+ * @param params.name - New name (optional)
80
+ * @param params.goal - New goal (optional)
81
+ * @returns The updated Workflow object
82
+ */
83
+ update(params: {
84
+ id: number | string;
85
+ name?: string;
86
+ goal?: string;
87
+ }): Promise<Workflow>;
88
+ /**
89
+ * Delete a workflow.
90
+ * @param params - Parameters object
91
+ * @param params.id - The workflow ID to delete
92
+ */
93
+ delete(params: {
94
+ id: number | string;
95
+ }): Promise<void>;
96
+ /**
97
+ * Set a workflow to running state.
98
+ *
99
+ * This activates the workflow so it can process triggers and execute tasks.
100
+ *
101
+ * @param params - Parameters object
102
+ * @param params.id - The workflow ID
103
+ */
104
+ setRunning(params: {
105
+ id: number | string;
106
+ }): Promise<void>;
107
+ /**
108
+ * Connect edges in the workflow graph.
109
+ * @param params - Parameters object
110
+ * @param params.id - The workflow ID
111
+ * @param params.edges - Array of edges to add
112
+ */
113
+ connect(params: {
114
+ id: number | string;
115
+ edges: Edge[];
116
+ }): Promise<void>;
117
+ /**
118
+ * Sync workflow with declarative configuration.
119
+ *
120
+ * This allows updating triggers, tasks, and edges in a single call.
121
+ * Note: For creating triggers, prefer using the triggers API directly
122
+ * as the sync endpoint has known limitations.
123
+ *
124
+ * @param params - Parameters object
125
+ * @param params.id - The workflow ID
126
+ * @param params.triggers - Array of trigger definitions (optional)
127
+ * @param params.tasks - Array of task definitions (optional)
128
+ * @param params.edges - Array of edge definitions (optional)
129
+ */
130
+ sync(params: {
131
+ id: number | string;
132
+ triggers?: TriggerDefinition[];
133
+ tasks?: TaskDefinition[];
134
+ edges?: EdgeDefinition[];
135
+ }): Promise<void>;
136
+ private syncInternal;
137
+ private getIntegrationConnectionId;
138
+ private getTriggerName;
139
+ private resolveEdgeRef;
140
+ private resolveNodeId;
141
+ }
142
+ //# sourceMappingURL=workflows-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows-api.d.ts","sourceRoot":"","sources":["../src/workflows-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EACV,cAAc,EAEd,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,IAAI,EAGL,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,cAAc;IAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACG,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;IA4BvD;;;;;OAKG;IACG,GAAG,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;IA8C7D;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAWjC;;;;;;;OAOG;IACG,MAAM,CAAC,MAAM,EAAE;QACnB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,QAAQ,CAAC;IAWrB;;;;OAIG;IACG,MAAM,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D;;;;;;;OAOG;IACG,UAAU,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhE;;;;;OAKG;IACG,OAAO,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB5E;;;;;;;;;;;;OAYG;IACG,IAAI,CAAC,MAAM,EAAE;QACjB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;QAC/B,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;QACzB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;KAC1B,GAAG,OAAO,CAAC,IAAI,CAAC;YAWH,YAAY;IA8H1B,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,aAAa;CAQtB"}
@@ -0,0 +1,357 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowsAPI = void 0;
4
+ const workflow_1 = require("./workflow");
5
+ /**
6
+ * API for managing workflows on the OpenServ platform.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const client = new PlatformClient({ apiKey: 'your-key' });
11
+ *
12
+ * // Create a workflow
13
+ * const workflow = await client.workflows.create({
14
+ * name: 'My Workflow',
15
+ * goal: 'Process data automatically',
16
+ * agentIds: [123, 456]
17
+ * });
18
+ *
19
+ * // List all workflows
20
+ * const workflows = await client.workflows.list();
21
+ *
22
+ * // Get a specific workflow
23
+ * const workflow = await client.workflows.get({ id: 789 });
24
+ * ```
25
+ */
26
+ class WorkflowsAPI {
27
+ client;
28
+ constructor(client) {
29
+ this.client = client;
30
+ }
31
+ /**
32
+ * Create a new workflow.
33
+ *
34
+ * Can create an empty workflow or a fully configured one with triggers, tasks, and edges.
35
+ *
36
+ * @param config - Workflow configuration
37
+ * @param config.name - Name of the workflow
38
+ * @param config.goal - Goal/description of what the workflow does
39
+ * @param config.agentIds - Array of agent IDs to include in the workflow
40
+ * @param config.triggers - Optional array of trigger definitions
41
+ * @param config.tasks - Optional array of task definitions
42
+ * @param config.edges - Optional array of edge definitions connecting nodes
43
+ * @returns The created Workflow object
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // Simple workflow
48
+ * const workflow = await client.workflows.create({
49
+ * name: 'Data Pipeline',
50
+ * goal: 'Process incoming data',
51
+ * agentIds: [123]
52
+ * });
53
+ *
54
+ * // Workflow with tasks
55
+ * const workflow = await client.workflows.create({
56
+ * name: 'Data Pipeline',
57
+ * goal: 'Process incoming data',
58
+ * agentIds: [123],
59
+ * tasks: [{ name: 'process', agentId: 123, description: 'Process data' }]
60
+ * });
61
+ * ```
62
+ */
63
+ async create(config) {
64
+ // Convert agentIds to the format expected by the API
65
+ const agents = config.agentIds.map((id) => ({
66
+ id: typeof id === "string" ? parseInt(id) : id,
67
+ }));
68
+ // First create the workspace
69
+ const data = await this.client.post("/workspaces?isBlank=true", {
70
+ name: config.name,
71
+ goal: config.goal,
72
+ agents,
73
+ type: "node-ui",
74
+ });
75
+ const workflowId = data.id;
76
+ // If declarative config provided, sync it
77
+ if (config.triggers || config.tasks || config.edges) {
78
+ await this.syncInternal(workflowId, config);
79
+ }
80
+ // Fetch and return the complete workflow
81
+ return this.get({ id: workflowId });
82
+ }
83
+ /**
84
+ * Get a workflow by ID.
85
+ * @param params - Parameters object
86
+ * @param params.id - The workflow ID
87
+ * @returns The Workflow object with full data including triggers, tasks, and edges
88
+ */
89
+ async get(params) {
90
+ const [workspace, tasks] = await Promise.all([
91
+ this.client.get(`/workspaces/${params.id}`),
92
+ this.client
93
+ .get(`/workspaces/${params.id}/tasks`)
94
+ .catch(() => []),
95
+ ]);
96
+ // Extract triggers from workspace response (includes token in attributes.uiState)
97
+ // The separate /triggers endpoint returns integration types, not actual triggers
98
+ const workspaceTriggers = (workspace.triggers || []).map((t) => ({
99
+ id: t.id,
100
+ name: t.name,
101
+ description: t.description || undefined,
102
+ token: t.attributes?.uiState?.token,
103
+ integrationConnectionId: t.integrationConnection?.id || "",
104
+ props: t.props || {},
105
+ isActive: t.is_active,
106
+ state: t.state,
107
+ }));
108
+ const workflowData = {
109
+ id: workspace.id,
110
+ name: workspace.name,
111
+ goal: workspace.goal,
112
+ status: workspace.executionState || "draft",
113
+ triggers: workspaceTriggers,
114
+ tasks: tasks || [],
115
+ edges: workspace.workflow?.edges || [],
116
+ agents: workspace.agents || [],
117
+ };
118
+ return new workflow_1.Workflow(workflowData, this.client);
119
+ }
120
+ /**
121
+ * List all workflows owned by the authenticated user.
122
+ * @returns Array of Workflow objects
123
+ */
124
+ async list() {
125
+ const workspaces = await this.client.get("/workspaces");
126
+ const workflows = [];
127
+ for (const ws of workspaces) {
128
+ workflows.push(await this.get({ id: ws.id }));
129
+ }
130
+ return workflows;
131
+ }
132
+ /**
133
+ * Update workflow metadata.
134
+ * @param params - Parameters object
135
+ * @param params.id - The workflow ID to update
136
+ * @param params.name - New name (optional)
137
+ * @param params.goal - New goal (optional)
138
+ * @returns The updated Workflow object
139
+ */
140
+ async update(params) {
141
+ const { id, name, goal } = params;
142
+ // Get current workflow to preserve required fields
143
+ const current = await this.get({ id });
144
+ await this.client.put(`/workspaces/${id}`, {
145
+ name: name ?? current.name,
146
+ goal: goal ?? current.goal,
147
+ });
148
+ return this.get({ id });
149
+ }
150
+ /**
151
+ * Delete a workflow.
152
+ * @param params - Parameters object
153
+ * @param params.id - The workflow ID to delete
154
+ */
155
+ async delete(params) {
156
+ await this.client.delete(`/workspaces/${params.id}`);
157
+ }
158
+ /**
159
+ * Set a workflow to running state.
160
+ *
161
+ * This activates the workflow so it can process triggers and execute tasks.
162
+ *
163
+ * @param params - Parameters object
164
+ * @param params.id - The workflow ID
165
+ */
166
+ async setRunning(params) {
167
+ await this.client.put(`/workspaces/${params.id}/execution-state`, {
168
+ executionState: "running",
169
+ });
170
+ }
171
+ /**
172
+ * Connect edges in the workflow graph.
173
+ * @param params - Parameters object
174
+ * @param params.id - The workflow ID
175
+ * @param params.edges - Array of edges to add
176
+ */
177
+ async connect(params) {
178
+ // Get current workflow to merge edges
179
+ const currentWorkflow = await this.client.get(`/workspaces/${params.id}`);
180
+ const nodes = currentWorkflow.workflow?.nodes || [];
181
+ const newEdges = params.edges.map((edge) => ({
182
+ source: this.resolveNodeId(edge.from),
183
+ target: this.resolveNodeId(edge.to),
184
+ }));
185
+ await this.client.put(`/workspaces/${params.id}/workflow`, {
186
+ workflow: {
187
+ nodes,
188
+ edges: [...(currentWorkflow.workflow?.edges || []), ...newEdges],
189
+ },
190
+ });
191
+ }
192
+ /**
193
+ * Sync workflow with declarative configuration.
194
+ *
195
+ * This allows updating triggers, tasks, and edges in a single call.
196
+ * Note: For creating triggers, prefer using the triggers API directly
197
+ * as the sync endpoint has known limitations.
198
+ *
199
+ * @param params - Parameters object
200
+ * @param params.id - The workflow ID
201
+ * @param params.triggers - Array of trigger definitions (optional)
202
+ * @param params.tasks - Array of task definitions (optional)
203
+ * @param params.edges - Array of edge definitions (optional)
204
+ */
205
+ async sync(params) {
206
+ await this.syncInternal(params.id, {
207
+ name: "",
208
+ goal: "",
209
+ agentIds: [],
210
+ triggers: params.triggers,
211
+ tasks: params.tasks,
212
+ edges: params.edges,
213
+ });
214
+ }
215
+ async syncInternal(workflowId, config) {
216
+ // Build the sync payload
217
+ const syncPayload = {};
218
+ // Get current workflow state for ID mapping
219
+ const currentTriggers = await this.client
220
+ .get(`/workspaces/${workflowId}/triggers`)
221
+ .catch(() => []);
222
+ const currentTasks = await this.client
223
+ .get(`/workspaces/${workflowId}/tasks`)
224
+ .catch(() => []);
225
+ // Map names to IDs for existing resources
226
+ const triggerNameToId = new Map();
227
+ const taskNameToId = new Map();
228
+ for (const t of currentTriggers || []) {
229
+ triggerNameToId.set(t.name || t.description, t.id);
230
+ }
231
+ for (const t of currentTasks || []) {
232
+ taskNameToId.set(t.name || t.description, t.id);
233
+ }
234
+ // Build triggers array with IDs
235
+ if (config.triggers) {
236
+ syncPayload.triggers = config.triggers.map((t) => ({
237
+ id: t.id || triggerNameToId.get(t.name) || `new-${t.name}`,
238
+ name: t.name,
239
+ description: t.name,
240
+ // Use integrationConnectionId if provided, otherwise fall back to type-based lookup
241
+ integrationConnectionId: t.integrationConnectionId || this.getIntegrationConnectionId(t.type),
242
+ // trigger_name is required by the sync endpoint
243
+ // Different triggers use different names: manual uses "on_event", webhook uses "on_request"
244
+ trigger_name: this.getTriggerName(t.type),
245
+ props: t.props || {},
246
+ attributes: {},
247
+ }));
248
+ }
249
+ // Build tasks array with IDs
250
+ if (config.tasks) {
251
+ syncPayload.tasks = config.tasks.map((t) => {
252
+ const existingId = t.id || taskNameToId.get(t.name);
253
+ return {
254
+ id: existingId || 0, // 0 means create new
255
+ description: t.description,
256
+ body: t.body || t.description,
257
+ input: t.input || "",
258
+ assigneeAgentId: typeof t.agentId === "string" ? parseInt(t.agentId) : t.agentId,
259
+ status: "to-do",
260
+ metadata: null,
261
+ attributes: { name: t.name },
262
+ outputOptions: {
263
+ default: {
264
+ name: "Task Output",
265
+ type: "text",
266
+ instructions: "Complete the task and provide output",
267
+ },
268
+ },
269
+ };
270
+ });
271
+ }
272
+ // Build workflow graph (nodes + edges)
273
+ if (config.edges || config.triggers || config.tasks) {
274
+ const nodes = [];
275
+ const edges = [];
276
+ // Add trigger nodes
277
+ if (config.triggers) {
278
+ for (const t of config.triggers) {
279
+ const triggerId = t.id || triggerNameToId.get(t.name) || `new-${t.name}`;
280
+ nodes.push({
281
+ id: `trigger-${t.name}`,
282
+ type: "trigger",
283
+ triggerId,
284
+ position: { x: 0, y: 0 },
285
+ inputPorts: [],
286
+ outputPorts: [{ id: "output", name: "Output" }],
287
+ });
288
+ }
289
+ }
290
+ // Add task nodes
291
+ if (config.tasks) {
292
+ for (const t of config.tasks) {
293
+ const taskId = t.id || taskNameToId.get(t.name) || 0;
294
+ nodes.push({
295
+ id: `task-${t.name}`,
296
+ type: "task",
297
+ taskId,
298
+ position: { x: 200, y: 0 },
299
+ inputPorts: [{ id: "input", name: "Input" }],
300
+ outputPorts: [{ id: "output", name: "Output" }],
301
+ });
302
+ }
303
+ }
304
+ // Add edges with required fields
305
+ if (config.edges) {
306
+ config.edges.forEach((e, i) => {
307
+ const sourceNode = this.resolveEdgeRef(e.from);
308
+ const targetNode = this.resolveEdgeRef(e.to);
309
+ edges.push({
310
+ id: `edge-${i}`,
311
+ source: sourceNode,
312
+ target: targetNode,
313
+ sourcePort: "output",
314
+ targetPort: "input",
315
+ });
316
+ });
317
+ }
318
+ syncPayload.workflow = { nodes, edges };
319
+ }
320
+ // Call the sync endpoint
321
+ await this.client.put(`/workspaces/${workflowId}/sync`, syncPayload);
322
+ }
323
+ getIntegrationConnectionId(type) {
324
+ if (!type)
325
+ return "";
326
+ const mapping = {
327
+ x402: "x402-trigger",
328
+ webhook: "webhook-trigger",
329
+ cron: "cron-trigger",
330
+ manual: "manual-trigger",
331
+ };
332
+ return mapping[type] || type;
333
+ }
334
+ getTriggerName(type) {
335
+ if (!type)
336
+ return "on_request";
337
+ const mapping = {
338
+ x402: "on_payment",
339
+ webhook: "on_request",
340
+ cron: "periodically",
341
+ manual: "on_event",
342
+ };
343
+ return mapping[type] || "on_request";
344
+ }
345
+ resolveEdgeRef(ref) {
346
+ // Convert 'trigger:name' or 'task:name' to node ID
347
+ const [type, name] = ref.split(":");
348
+ return `${type}-${name}`;
349
+ }
350
+ resolveNodeId(ref) {
351
+ if (typeof ref === "string") {
352
+ return this.resolveEdgeRef(ref);
353
+ }
354
+ return `${ref.type}-${ref.id}`;
355
+ }
356
+ }
357
+ exports.WorkflowsAPI = WorkflowsAPI;
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@openserv-labs/client",
3
+ "version": "1.0.0",
4
+ "description": "OpenServ Platform Client - Manage agents, workflows, tasks, and triggers via the OpenServ API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "tsc --watch",
10
+ "check-types": "tsc --noEmit",
11
+ "prepublishOnly": "npm run build && npm run lint && npm run check-types",
12
+ "prepare": "npm run build",
13
+ "lint": "eslint .",
14
+ "lint:fix": "eslint . --fix",
15
+ "format": "prettier --write \"**/*.{ts,json,md}\"",
16
+ "format:check": "prettier --check \"**/*.{ts,json,md}\"",
17
+ "test": "node --import tsx --test test/**/*.test.ts",
18
+ "test:unit": "node --import tsx --test test/unit/**/*.test.ts"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/openserv-labs/client.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/openserv-labs/client/issues"
26
+ },
27
+ "homepage": "https://github.com/openserv-labs/client#readme",
28
+ "keywords": [
29
+ "openserv",
30
+ "api",
31
+ "client",
32
+ "platform",
33
+ "workflows",
34
+ "agents",
35
+ "typescript"
36
+ ],
37
+ "author": "OpenServ Labs",
38
+ "license": "MIT",
39
+ "dependencies": {
40
+ "axios": "^1.6.8",
41
+ "ethers": "^6.16.0",
42
+ "viem": "^2.45.1",
43
+ "x402-fetch": "^1.1.0"
44
+ },
45
+ "devDependencies": {
46
+ "@eslint/js": "^9.39.2",
47
+ "@tsconfig/strictest": "^2.0.3",
48
+ "@types/node": "^22.10.2",
49
+ "dotenv": "^16.4.5",
50
+ "eslint": "^9.39.2",
51
+ "eslint-config-prettier": "^9.1.0",
52
+ "eslint-plugin-prettier": "^5.1.3",
53
+ "prettier": "^3.2.5",
54
+ "tsx": "^4.19.2",
55
+ "typescript": "^5.4.2",
56
+ "typescript-eslint": "^8.33.0"
57
+ },
58
+ "files": [
59
+ "dist",
60
+ "README.md",
61
+ "LICENSE"
62
+ ],
63
+ "publishConfig": {
64
+ "access": "public",
65
+ "registry": "https://registry.npmjs.org/"
66
+ },
67
+ "engines": {
68
+ "node": ">=18.0.0"
69
+ }
70
+ }