{"_id":"@apito-io/js-plugin-build-sdk","name":"@apito-io/js-plugin-build-sdk","dist-tags":{"latest":"0.3.0"},"versions":{"0.3.0":{"name":"@apito-io/js-plugin-build-sdk","version":"0.3.0","description":"JavaScript SDK for building Apito HashiCorp plugins (plugin build tooling)","main":"dist/main.js","types":"dist/main.d.ts","scripts":{"build":"node build.js","dev":"node build.js --dev","test":"npm run build && node test-handshake.js","test:handshake":"npm run build && node test-handshake.js"},"keywords":["apito","plugin","graphql","hashicorp","grpc"],"author":{"name":"Apito Inc"},"license":"MIT","dependencies":{"@grpc/grpc-js":"^1.14.3","@grpc/proto-loader":"^0.8.0"},"devDependencies":{"typescript":"~5.9.3"},"repository":{"type":"git","url":"git+https://github.com/apito-io/js-plugin-build-sdk.git"},"publishConfig":{"access":"public"},"_id":"@apito-io/js-plugin-build-sdk@0.3.0","gitHead":"048cb331ea47deb8428a05a9625b00f51b823212","bugs":{"url":"https://github.com/apito-io/js-plugin-build-sdk/issues"},"homepage":"https://github.com/apito-io/js-plugin-build-sdk#readme","_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-Y5/N4D/Y32dX9V3xXlLVxnRgvOBdpih3/E7TV7HYY9b16xXPRG2gK6q/CI8jRfyYXWlqqgUBmZ0329brpHhpoA==","shasum":"b3ab1f3bd3201c84f1a81da963c64cd1a1934d74","tarball":"https://registry.npmjs.org/@apito-io/js-plugin-build-sdk/-/js-plugin-build-sdk-0.3.0.tgz","fileCount":10,"unpackedSize":106511,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC1lqjCKjvLxcMkmEGD1ODqF31v0j+HWfNdkzofR95rfAIgMyiu0QdHFQbLZUNOEGhNBgX3ZL9FLeNZbDV5DAZdj00="}]},"_npmUser":{"name":"sh0umik","email":"fahim.shoumik@gmail.com"},"directories":{},"maintainers":[{"name":"sh0umik","email":"fahim.shoumik@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/js-plugin-build-sdk_0.3.0_1775106126559_0.6213558586111778"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-02T05:02:06.455Z","0.3.0":"2026-04-02T05:02:06.710Z","modified":"2026-04-02T05:02:06.921Z"},"maintainers":[{"name":"sh0umik","email":"fahim.shoumik@gmail.com"}],"description":"JavaScript SDK for building Apito HashiCorp plugins (plugin build tooling)","homepage":"https://github.com/apito-io/js-plugin-build-sdk#readme","keywords":["apito","plugin","graphql","hashicorp","grpc"],"repository":{"type":"git","url":"git+https://github.com/apito-io/js-plugin-build-sdk.git"},"author":{"name":"Apito Inc"},"bugs":{"url":"https://github.com/apito-io/js-plugin-build-sdk/issues"},"license":"MIT","readme":"# Apito JavaScript Plugin Build SDK\n\nA simplified JavaScript/Node.js SDK for building HashiCorp plugins for the Apito Engine. This SDK abstracts away all the boilerplate code and provides a clean, easy-to-use interface for plugin developers.\n\n## Installation\n\n```bash\nnpm install @apito-io/js-plugin-build-sdk\n# or\nyarn add @apito-io/js-plugin-build-sdk\n```\n\n## Quick Start\n\n### Basic Plugin Structure\n\n```javascript\nconst { init } = require(\"@apito-io/js-plugin-build-sdk\");\nconst {\n  StringField,\n  FieldWithArgs,\n  StringArg,\n  GETEndpoint,\n  ObjectSchema,\n  StringSchema,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nasync function main() {\n  // Initialize the plugin\n  const plugin = init(\"my-awesome-plugin\", \"1.0.0\", \"your-api-key\");\n\n  // Register GraphQL queries\n  plugin.registerQuery(\n    \"hello\",\n    FieldWithArgs(\"String\", \"Returns a greeting\", {\n      name: StringArg(\"Name to greet\"),\n    }),\n    helloResolver\n  );\n\n  // Register GraphQL mutations\n  plugin.registerMutation(\n    \"createUser\",\n    FieldWithArgs(\"String\", \"Creates a new user\", {\n      name: StringArg(\"User name\"),\n      email: StringArg(\"User email\"),\n    }),\n    createUserResolver\n  );\n\n  // Register REST API endpoints\n  plugin.registerRESTAPI(\n    GETEndpoint(\"/hello\", \"Simple hello endpoint\")\n      .withResponseSchema(\n        ObjectSchema({\n          message: StringSchema(\"Hello message\"),\n          timestamp: StringSchema(\"Current timestamp\"),\n        })\n      )\n      .build(),\n    helloRESTHandler\n  );\n\n  // Register custom functions\n  plugin.registerFunction(\"processData\", processDataFunction);\n\n  // Start the plugin server\n  await plugin.serve();\n}\n\n// GraphQL Resolvers\nasync function helloResolver(context, args) {\n  const name = args.name || \"World\";\n  return `Hello, ${name}!`;\n}\n\nasync function createUserResolver(context, args) {\n  const { name, email } = args;\n  return `Created user: ${name} <${email}>`;\n}\n\n// REST Handlers\nasync function helloRESTHandler(context, args) {\n  return {\n    message: \"Hello from REST API!\",\n    timestamp: new Date().toISOString(),\n  };\n}\n\n// Custom Functions\nasync function processDataFunction(context, args) {\n  return \"Data processed successfully\";\n}\n\n// Start the plugin\nmain().catch(console.error);\n```\n\n## API Reference\n\n### Plugin Initialization\n\n#### `init(name, version, apiKey)`\n\nInitializes a new plugin instance.\n\n- `name`: Plugin name (string)\n- `version`: Plugin version (string)\n- `apiKey`: API key for authentication (string)\n\nReturns a `Plugin` instance.\n\n### GraphQL Schema Registration\n\n#### Individual Registration\n\n```javascript\n// Register a single query\nplugin.registerQuery(name, field, resolver);\n\n// Register a single mutation\nplugin.registerMutation(name, field, resolver);\n```\n\n#### Batch Registration\n\n```javascript\n// Register multiple queries at once\nconst queries = {\n  getUser: FieldWithArgs(\"String\", \"Get user by ID\", {\n    id: StringArg(\"User ID\"),\n  }),\n  getUsers: StringField(\"Get all users\"),\n};\n\nconst resolvers = {\n  getUser: getUserResolver,\n  getUsers: getUsersResolver,\n};\n\nplugin.registerQueries(queries, resolvers);\n```\n\n### GraphQL Field Helpers\n\n#### Basic Fields\n\n```javascript\nconst {\n  StringField,\n  IntField,\n  BooleanField,\n  FloatField,\n  ListField,\n  NonNullField,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nStringField(\"Description\"); // String\nIntField(\"Description\"); // Int\nBooleanField(\"Description\"); // Boolean\nFloatField(\"Description\"); // Float\nListField(\"String\", \"Description\"); // [String]\nNonNullField(\"String\", \"Description\"); // String!\nNonNullListField(\"String\", \"Description\"); // [String!]!\n```\n\n#### Fields with Arguments\n\n```javascript\nconst {\n  FieldWithArgs,\n  StringArg,\n  IntArg,\n  BooleanArg,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nFieldWithArgs(\"String\", \"Get user greeting\", {\n  name: StringArg(\"User name\"),\n  age: IntArg(\"User age\"),\n  active: BooleanArg(\"Is user active\"),\n});\n```\n\n#### Object Fields\n\n```javascript\nconst { ObjectField, ObjectArg } = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nObjectField(\"User object\", {\n  id: StringArg(\"User ID\"),\n  name: StringArg(\"User name\"),\n  email: StringArg(\"User email\"),\n});\n```\n\n#### Complex Object Types\n\n```javascript\nconst { NewObjectType } = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\n// Define a complex object type\nconst userType = NewObjectType(\"User\", \"A user in the system\")\n  .addStringField(\"id\", \"User ID\", false) // Required field\n  .addStringField(\"name\", \"User name\", false) // Required field\n  .addStringField(\"email\", \"User email\", true) // Optional field\n  .addBooleanField(\"active\", \"Is user active\", false)\n  .build();\n\n// Use in GraphQL queries\nplugin.registerQuery(\n  \"getUserProfile\",\n  FieldWithArgs(\"User\", \"Get user profile\", {\n    userId: StringArg(\"User ID to fetch\"),\n  }),\n  getUserProfileResolver\n);\n```\n\n### REST API Registration\n\n#### Individual Registration\n\n```javascript\nconst {\n  GETEndpoint,\n  POSTEndpoint,\n  ObjectSchema,\n  StringSchema,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nconst endpoint = GETEndpoint(\"/users\", \"Get all users\")\n  .withResponseSchema(\n    ObjectSchema({\n      users: ArraySchema(\n        ObjectSchema({\n          id: StringSchema(\"User ID\"),\n          name: StringSchema(\"User name\"),\n        })\n      ),\n    })\n  )\n  .build();\n\nplugin.registerRESTAPI(endpoint, getUsersHandler);\n```\n\n#### Batch Registration\n\n```javascript\nconst endpoints = [\n  GETEndpoint(\"/health\", \"Health check\").build(),\n  POSTEndpoint(\"/users\", \"Create user\").build(),\n];\n\nconst handlers = {\n  \"GET_/health\": healthHandler,\n  \"POST_/users\": createUserHandler,\n};\n\nplugin.registerRESTAPIs(endpoints, handlers);\n```\n\n### REST Endpoint Builders\n\n```javascript\nconst {\n  GETEndpoint,\n  POSTEndpoint,\n  PUTEndpoint,\n  DELETEEndpoint,\n  PATCHEndpoint,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nGETEndpoint(path, description);\nPOSTEndpoint(path, description);\nPUTEndpoint(path, description);\nDELETEEndpoint(path, description);\nPATCHEndpoint(path, description);\n```\n\n### REST Schema Helpers\n\n```javascript\nconst {\n  ObjectSchema,\n  ArraySchema,\n  StringSchema,\n  IntegerSchema,\n  BooleanSchema,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nObjectSchema(properties); // Object schema\nArraySchema(itemSchema); // Array schema\nStringSchema(description); // String schema\nIntegerSchema(description); // Integer schema\nBooleanSchema(description); // Boolean schema\n```\n\n### Function Registration\n\n#### Individual Registration\n\n```javascript\nplugin.registerFunction(\"processData\", async (context, args) => {\n  // Function logic here\n  return \"result\";\n});\n```\n\n#### Batch Registration\n\n```javascript\nconst functions = {\n  processData: processDataFunction,\n  validateData: validateDataFunction,\n  transformData: transformDataFunction,\n};\n\nplugin.registerFunctions(functions);\n```\n\n### Utility Functions\n\n#### Argument Extraction\n\n```javascript\nconst {\n  getStringArg,\n  getIntArg,\n  getBoolArg,\n  getObjectArg,\n  getArrayArg,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nasync function myResolver(context, args) {\n  const name = getStringArg(args, \"name\", \"Default Name\");\n  const age = getIntArg(args, \"age\", 0);\n  const active = getBoolArg(args, \"active\", true);\n  const user = getObjectArg(args, \"user\", {});\n  const tags = getArrayArg(args, \"tags\", []);\n\n  return { name, age, active, user, tags };\n}\n```\n\n#### REST Parameter Extraction\n\n```javascript\nconst {\n  getPathParam,\n  getQueryParam,\n  getBodyParam,\n  logRESTArgs,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nasync function myRESTHandler(context, args) {\n  // Debug log all arguments\n  logRESTArgs(\"myHandler\", args);\n\n  // Extract different parameter types\n  const userId = getPathParam(args, \":id\"); // Path parameter\n  const search = getQueryParam(args, \"search\"); // Query parameter\n  const userData = getBodyParam(args, \"user\"); // Body parameter\n\n  return { userId, search, userData };\n}\n```\n\n### Function Signatures\n\n```javascript\n/**\n * @typedef {Function} ResolverFunc\n * @param {Object} context - Request context\n * @param {Object} args - Function arguments\n * @returns {Promise<any>} Resolver result\n */\n\n/**\n * @typedef {Function} RESTHandlerFunc\n * @param {Object} context - Request context\n * @param {Object} args - Function arguments\n * @returns {Promise<any>} Handler result\n */\n\n/**\n * @typedef {Function} FunctionHandlerFunc\n * @param {Object} context - Request context\n * @param {Object} args - Function arguments\n * @returns {Promise<any>} Function result\n */\n```\n\n## Advanced Examples\n\n### Complex GraphQL Query with Nested Objects\n\n```javascript\nconst {\n  FieldWithArgs,\n  ObjectArg,\n  ListArg,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nplugin.registerQuery(\n  \"processComplexData\",\n  FieldWithArgs(\"String\", \"Process complex input data\", {\n    user: ObjectArg(\"Single user\", {\n      id: IntArg(\"User ID\"),\n      name: StringArg(\"User name\"),\n      email: StringArg(\"User email\"),\n      active: BooleanArg(\"Is user active\"),\n    }),\n    tags: ListArg(\"String\", \"Array of tags\"),\n    users: ListArg(\"Object\", \"Array of user objects\"),\n  }),\n  processComplexDataResolver\n);\n\nasync function processComplexDataResolver(context, args) {\n  const { user, tags, users } = args;\n\n  // Process the complex data\n  const result = {\n    processedUser: user,\n    tagCount: tags.length,\n    userCount: users.length,\n    timestamp: new Date().toISOString(),\n  };\n\n  return JSON.stringify(result);\n}\n```\n\n### REST API with Complex Schema\n\n```javascript\nconst {\n  POSTEndpoint,\n  ObjectSchema,\n  ArraySchema,\n} = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\nconst endpoint = POSTEndpoint(\"/api/users\", \"Create new user\")\n  .withRequestSchema(\n    ObjectSchema({\n      user: ObjectSchema({\n        name: StringSchema(\"User name\"),\n        email: StringSchema(\"User email\"),\n        age: IntegerSchema(\"User age\"),\n        metadata: ObjectSchema({\n          department: StringSchema(\"User department\"),\n          role: StringSchema(\"User role\"),\n        }),\n      }),\n      tags: ArraySchema(StringSchema(\"Tag name\")),\n    })\n  )\n  .withResponseSchema(\n    ObjectSchema({\n      success: BooleanSchema(\"Operation success\"),\n      user_id: StringSchema(\"Created user ID\"),\n      message: StringSchema(\"Response message\"),\n    })\n  )\n  .build();\n\nplugin.registerRESTAPI(endpoint, createUserWithMetadataHandler);\n\nasync function createUserWithMetadataHandler(context, args) {\n  const { logRESTArgs, getBodyParam } = require(\"@apito-io/js-plugin-build-sdk/helpers\");\n\n  logRESTArgs(\"createUserWithMetadata\", args);\n\n  const user = getBodyParam(args, \"user\");\n  const tags = getBodyParam(args, \"tags\");\n\n  // Create user logic here\n  const userId = `user_${Date.now()}`;\n\n  return {\n    success: true,\n    user_id: userId,\n    message: `User ${user.name} created successfully with ${tags.length} tags`,\n  };\n}\n```\n\n### Health Checks\n\n```javascript\n// Register custom health checks\nplugin.registerHealthCheck(async (context) => {\n  // Check database connection\n  const dbStatus = await checkDatabase();\n\n  return {\n    status: dbStatus.connected ? \"healthy\" : \"unhealthy\",\n    database: {\n      connected: dbStatus.connected,\n      latency: dbStatus.latency,\n    },\n  };\n});\n\nplugin.registerHealthCheck(async (context) => {\n  // Check external API\n  const apiStatus = await checkExternalAPI();\n\n  return {\n    status: apiStatus.available ? \"healthy\" : \"degraded\",\n    external_api: {\n      available: apiStatus.available,\n      response_time: apiStatus.responseTime,\n    },\n  };\n});\n```\n\n## Error Handling\n\nAll resolver functions, REST handlers, and custom functions should handle errors gracefully:\n\n```javascript\nasync function myResolver(context, args) {\n  try {\n    // Validate input\n    const name = getStringArg(args, \"name\");\n    if (!name) {\n      throw new Error(\"Name is required\");\n    }\n\n    // Process data\n    const result = await processData(name);\n    return result;\n  } catch (error) {\n    console.error(\"Resolver error:\", error);\n    throw error; // Re-throw to be handled by the SDK\n  }\n}\n```\n\n## Context Usage\n\nThe context parameter provides access to the request context:\n\n```javascript\nasync function myResolver(context, args) {\n  // Access context information\n  const pluginId = context.plugin_id;\n  const projectId = context.project_id;\n\n  console.log(\n    `Processing request for plugin ${pluginId} in project ${projectId}`\n  );\n\n  // Use context for request-scoped operations\n  return processWithContext(context, args);\n}\n```\n\n## Building and Running\n\n1. Create your plugin using the SDK\n2. Install dependencies:\n   ```bash\n   npm install\n   ```\n3. Run your plugin:\n   ```bash\n   node main.js\n   ```\n4. The Apito Engine will execute your plugin as a HashiCorp plugin\n\n## Environment Variables\n\nThe SDK automatically handles environment variables passed by the engine:\n\n- `PLUGIN_GRPC_PORT`: gRPC server port (automatically assigned)\n- Custom environment variables from the engine configuration\n\n## Debugging\n\nEnable debug logging by setting environment variables:\n\n```bash\nNODE_ENV=development node main.js\n```\n\nThe SDK provides structured logging for:\n\n- Plugin initialization\n- Schema registration\n- Function execution\n- Error handling\n\n## Best Practices\n\n1. **Use descriptive names** for GraphQL fields and REST endpoints\n2. **Validate input data** in your resolvers and handlers\n3. **Handle errors gracefully** and return meaningful error messages\n4. **Use the utility functions** for consistent argument extraction\n5. **Add proper JSDoc comments** for better IDE support\n6. **Test your plugins** thoroughly before deployment\n7. **Use async/await** for better error handling and readability\n\n## TypeScript Support\n\nWhile this SDK is written in JavaScript, you can use it with TypeScript:\n\n```typescript\nimport { init } from \"@apito-io/js-plugin-build-sdk\";\nimport {\n  StringField,\n  FieldWithArgs,\n  StringArg,\n} from \"@apito-io/js-plugin-build-sdk/helpers\";\n\ninterface ResolverContext {\n  plugin_id: string;\n  project_id: string;\n}\n\ninterface HelloArgs {\n  name?: string;\n}\n\nasync function helloResolver(\n  context: ResolverContext,\n  args: HelloArgs\n): Promise<string> {\n  const name = args.name || \"World\";\n  return `Hello, ${name}!`;\n}\n\n// Rest of your plugin code...\n```\n\n## License\n\nThis SDK is part of the Apito Engine project.\n\n## Support\n\nFor questions and support, please visit the [Apito Documentation](https://docs.apito.io) or contact our support team.\n","readmeFilename":"README.md","_rev":"1-cd3916f70127dc87dcd2b4e9b16461f5"}