kintone-as-code
v0.6.2
Published
A CLI tool for managing kintone applications as code with type-safe TypeScript schemas
Maintainers
Readme
kintone-as-code
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 filesapps/{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
npm install -g kintone-as-codePrerequisites
- Node.js 18 or higher
- kintone environment with API access
Quick Start
1. Initialize project
kintone-as-code initThis creates a kintone-as-code.config.js file with your environment settings.
2. Export an existing app
# 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-subtableThis generates:
apps/customer-app.schema.ts- Fully typed field definitionsapps/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_TABLEdisplayFields are exposed minimally viacreateTableSubField('parent.child')(in/not in only) - With
--include-subtable, subtable child fields are exposed with the same minimal API
- With
3. Apply changes to existing app
kintone-as-code apply --app-id 123 --schema apps/customer-app.schema.tsThis updates the app with any schema changes and automatically adds new fields.
4. Create a new app from schema
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:
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:
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, 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:
kintone-as-code init [options]
Options:
-f, --force Force overwrite existing filesexport
Export kintone app configuration to TypeScript:
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 generationThe export command now generates three files by default:
- Field Schema (
{name}.schema.ts) - Field definitions and configurations - Record Schema (
{name}.record-schema.ts) - Type-safe record validation with Effect Schema - Query Builder (
{name}.query.ts) - Type-safe query builder for kintone REST API
apply
Apply schema changes to an existing kintone app:
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 nameFeatures:
- 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:
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 nameFeatures:
- 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:
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)
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)
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:
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
// 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
- Version Control: Commit your schema files to track app configuration changes
- Centralized APP_IDS: Manage app IDs in
utils/app-ids.ts(kept up-to-date by export) - Type Safety: Leverage TypeScript's type checking to catch configuration errors early
- Code Review: Review schema changes as part of your development process
- Record Validation: Use generated record schemas in your customization code for type-safe data handling
License
MIT
