UNPKG

kintone-as-code

Version:

A CLI tool for managing kintone applications as code with type-safe TypeScript schemas

476 lines (368 loc) 13.6 kB
# kintone-as-code [![npm version](https://badge.fury.io/js/kintone-as-code.svg)](https://badge.fury.io/js/kintone-as-code) [![CI](https://github.com/kimotokensei/kintone-as-code/actions/workflows/ci.yml/badge.svg)](https://github.com/kimotokensei/kintone-as-code/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [日本語](README.ja.md) Manage kintone app configurations as code with type safety using Effect-TS. ## Architecture (Summary) - Functional Core, Imperative Shell - Core (pure functions in `src/query/*`): expressions, fields, FP builder, validation - Shell (side effects): CLI/commands and code generator - Public API is FP-only. No OO facade is provided. The method-chaining `createQuery()` is a helper emitted in generated files `apps/{name}.query.ts`, not a public package API. ## Features - 🔒 **Type-safe** - Full TypeScript support with kintone-effect-schema - 📝 **Export from kintone** - Generate schema files from existing apps - 🚀 **Apply changes** - Update existing apps with schema changes and automatically add new fields - ✨ **Create apps** - Create new kintone apps from schema definitions - 🔧 **Environment management** - Support multiple kintone environments - 🎯 **Effect-TS powered** - Leverage the power of Effect-TS for schema validation - 📋 **Record Schema Generation** - Generates static, copy-paste-friendly record schemas for customization ## Installation ```bash npm install -g kintone-as-code ``` ## Prerequisites - Node.js 18 or higher - kintone environment with API access ## Quick Start ### 1. Initialize project ```bash kintone-as-code init ``` This creates a `kintone-as-code.config.js` file with your environment settings. ### 2. Export an existing app ```bash # Default: generates query and record-schema as well kintone-as-code export --app-id 123 --name customer-app # Suppress generation (backward-compatible --with-* also supported) kintone-as-code export --app-id 123 --name customer-app --no-query kintone-as-code export --app-id 123 --name customer-app --no-record-schema # Include related/subtable fields as dot-notation (minimal: in/not in only) kintone-as-code export --app-id 123 --name customer-app \ --include-related \ --include-subtable ``` This generates: - `apps/customer-app.schema.ts` - Fully typed field definitions - `apps/customer-app.record-schema.ts` - Static, type-safe record validation schema (copy-paste friendly) - `apps/customer-app.query.ts` - Type-safe query builder for kintone API (generated by default) - With `--include-related`, `REFERENCE_TABLE` displayFields are exposed minimally via `createTableSubField('parent.child')` (in/not in only) - With `--include-subtable`, subtable child fields are exposed with the same minimal API ### 3. Apply changes to existing app ```bash kintone-as-code apply --app-id 123 --schema apps/customer-app.schema.ts ``` This updates the app with any schema changes and automatically adds new fields. ### 4. Create a new app from schema ```bash kintone-as-code create --schema apps/customer-app.schema.ts --name "Customer App Copy" ``` This creates a new app with all fields defined in the schema. ### 5. Define app schema The exported schema uses kintone-effect-schema for complete type safety: ```typescript import { defineAppSchema } from 'kintone-as-code'; import { APP_IDS } from './utils/app-ids'; import type { SingleLineTextFieldProperties, NumberFieldProperties, SubtableFieldProperties, } from 'kintone-effect-schema'; // Individual field definitions with complete type information export const companyNameField: SingleLineTextFieldProperties = { type: 'SINGLE_LINE_TEXT', code: '会社名', label: '会社名', required: true, unique: true, maxLength: '100', }; export const revenueField: NumberFieldProperties = { type: 'NUMBER', code: '売上高', label: '年間売上高', unit: '円', unitPosition: 'AFTER', }; // Subtable with nested fields export const productsField: SubtableFieldProperties = { type: 'SUBTABLE', code: 'products', fields: { productName: { type: 'SINGLE_LINE_TEXT', code: 'productName', label: '商品名', required: true, }, price: { type: 'NUMBER', code: 'price', label: '単価', unit: '円', }, }, }; // App fields configuration export const appFieldsConfig = { properties: { 会社名: companyNameField, 売上高: revenueField, products: productsField, }, }; // App schema definition export default defineAppSchema({ // APP_IDS central registry (recommended to align with generated files) appId: APP_IDS.CUSTOMER_APP, name: 'Customer Management', description: 'Customer information management app', fieldsConfig: appFieldsConfig, }); ``` ## Configuration ### App ID management Use `utils/app-ids.ts` to centrally manage app IDs. It is automatically updated by the `export` command. ### Configuration File `kintone-as-code.config.js`: ```javascript export default { default: 'production', environments: { production: { auth: { baseUrl: process.env.KINTONE_BASE_URL, username: process.env.KINTONE_USERNAME, password: process.env.KINTONE_PASSWORD, }, }, development: { auth: { baseUrl: process.env.KINTONE_BASE_URL, username: process.env.KINTONE_USERNAME, password: process.env.KINTONE_PASSWORD, }, }, }, }; ``` ## Integration with kintone-effect-schema This tool is designed to work seamlessly with [kintone-effect-schema](https://github.com/Kensei-Kimoto/kintone-effect-schema), which provides: - Complete type definitions for all kintone field types - Runtime validation using Effect-TS - Support for Japanese field codes - Automatic handling of empty values ## Commands ### Docs index - Overview (IaC): `docs/overview.ja.md` - Config: `docs/config.ja.md` - Converter & Schemas: `docs/converter-and-schemas.ja.md` - Export/Apply/Create: `docs/export-apply-create.ja.md` - Query Builder: `docs/query-builder.ja.md` - Query Cookbook: `docs/query-cookbook.ja.md` - Architecture: `docs/architecture.ja.md` ### init Initialize a new kintone-as-code project: ```bash kintone-as-code init [options] Options: -f, --force Force overwrite existing files ``` ### export Export kintone app configuration to TypeScript: ```bash kintone-as-code export [options] Options: --app-id <id> App ID to export (required) --name <name> Schema file name (required) --env <env> Environment name --output <dir> Output directory (default: "apps") --with-record-schema Generate record schema file (default: true) --no-record-schema Skip record schema generation --with-query Generate query builder file (default: true) --no-query Skip query builder generation ``` The export command now generates three files by default: 1. **Field Schema** (`{name}.schema.ts`) - Field definitions and configurations 2. **Record Schema** (`{name}.record-schema.ts`) - Type-safe record validation with Effect Schema 3. **Query Builder** (`{name}.query.ts`) - Type-safe query builder for kintone REST API ### apply Apply schema changes to an existing kintone app: ```bash kintone-as-code apply [options] Options: --app-id <id> App ID to update (optional; if omitted, uses appId from schema) --schema <path> Path to schema file (required) --env <env> Environment name ``` Features: - Updates existing fields with type-safe validation - Automatically detects and adds new fields - Deploys changes after successful update ### create Create a new kintone app from a schema file: ```bash kintone-as-code create [options] Options: --schema <path> Path to schema file (required) --name <name> Override app name from schema --space <id> Create app in specific space --thread <id> Thread ID in the space (when creating inside a space) --env <env> Environment name ``` Features: - Creates new app with all fields defined in schema - Supports creating apps in specific spaces - Automatically deploys the app after creation ## Record Schema Usage The generated record schema provides type-safe validation for kintone records with automatic normalization: ```typescript import { KintoneRestAPIClient } from '@kintone/rest-api-client'; import { validateRecord, type AppRecord, } from './apps/customer-app.record-schema'; // Initialize client const client = new KintoneRestAPIClient({ baseUrl: process.env.KINTONE_BASE_URL!, auth: { username: process.env.KINTONE_USERNAME!, password: process.env.KINTONE_PASSWORD!, }, }); // Fetch and validate record with automatic normalization const response = await client.record.getRecord({ app: 123, id: 1, }); const validatedRecord: AppRecord = validateRecord(response.record); // validatedRecord is fully typed and normalized (no type assertions needed) // Empty strings in number fields → null, undefined → '', etc. ``` ### Example of generated Record Schema (simple) ```ts import { Schema } from 'effect'; import { SingleLineTextFieldSchema, NumberFieldSchema, decodeKintoneRecord, } from 'kintone-effect-schema'; // Static output example export const RecordSchema = Schema.Struct({ title: SingleLineTextFieldSchema, amount: NumberFieldSchema, }); export type AppRecord = Schema.Schema.Type<typeof RecordSchema>; export const validateRecord = (record: Record<string, unknown>): AppRecord => { const normalized = decodeKintoneRecord(record); return Schema.decodeUnknownSync(RecordSchema)(normalized); }; ``` ### JavaScript API Usage (Customization) ```typescript import { validateRecord, type AppRecord, } from './apps/customer-app.record-schema'; kintone.events.on('app.record.detail.show', (event) => { // Same function works for JavaScript API const validatedRecord: AppRecord = validateRecord(event.record); // Handles all empty value inconsistencies automatically return event; }); ``` ## Query Builder Usage The generated query builder provides type-safe query construction with IDE auto-completion: ```typescript import { QueryFields, createQuery } from './apps/customer-app.query'; import { and, or } from 'kintone-as-code'; // All field names are auto-completed const { 会社名, ステータス, 売上高, 担当者 } = QueryFields; // Build type-safe queries // OO facade (method-chain) const query = createQuery() .where( and( 会社名.like('*サイボウズ*'), 売上高.greaterThan(1000000), ステータス.in(['商談中', '受注']) ) ) .orderBy('売上高', 'desc') .limit(100) .build(); // Use with kintone REST API const client = new KintoneRestAPIClient({ /* ... */ }); // Functional API (pure functions) import { createQueryState, setWhere, appendOrder, withLimit, build, } from 'kintone-as-code'; const query2 = build( withLimit(100)( appendOrder( '売上高', 'desc' )( setWhere( and( 会社名.like('*サイボウズ*'), 売上高.greaterThan(1000000), ステータス.in(['商談中', '受注']) ) )(createQueryState()) ) ) ); const records = await client.record.getRecords({ app: 123, query: query, }); ``` ### Helper methods - Strings: `contains()/startsWith()/endsWith()` - Numbers, Date, DateTime, and Time: `between(min, max)` - Custom function names: `customDateFunction(name, ...args)` / `customUserFunction(name, ...args)` ### Query Features - **Type-safe field access**: All fields are typed based on their kintone field types - **Field-specific operators**: Only valid operators for each field type are available - **kintone functions**: Support for `TODAY()`, `LOGINUSER()`, `THIS_MONTH()`, etc. - **Complex conditions**: Combine with `and()`, `or()`, `not()` - **Auto-completion**: IDE provides suggestions for fields and methods Note: The query builder is not exposed as a public API. Internally we follow FP design; if we expose it in the future, the FP API will be the only supported style. ### Note: No `raw()` escape hatch Direct raw query insertion via `raw()` is not provided. Instead, use `contains/startsWith/endsWith`, `between(min, max)`, and `customDateFunction/customUserFunction` as escape hatches. ### Field Type Examples ```typescript // String fields support like/not like 会社名.like('*株式会社*'); 会社名.notLike('*test*'); // Number fields support comparison operators 売上高.greaterThan(1000000); 売上高.lessThanOrEqual(5000000); // Dropdown fields use in/not in ステータス.in(['商談中', '受注']); ステータス.notIn(['失注', 'キャンセル']); // Date fields support date functions 契約日.equals(TODAY()); 期限日.lessThan(FROM_TODAY(7, 'DAYS')); 登録日.in([THIS_MONTH()]); // User fields support user functions 担当者.equals(LOGINUSER()); 作成者.in(['user1', 'user2']); ``` ## Best Practices 1. **Version Control**: Commit your schema files to track app configuration changes 2. **Centralized APP_IDS**: Manage app IDs in `utils/app-ids.ts` (kept up-to-date by export) 3. **Type Safety**: Leverage TypeScript's type checking to catch configuration errors early 4. **Code Review**: Review schema changes as part of your development process 5. **Record Validation**: Use generated record schemas in your customization code for type-safe data handling ## License MIT