@izumisy-tailor/omakase-modules 0.2.0 → 0.4.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 (47) hide show
  1. package/README.md +0 -28
  2. package/docs/generated/README.md +35 -0
  3. package/docs/generated/_media/creating-modules.md +471 -0
  4. package/docs/{tutorials → generated/_media}/using-modules.md +69 -20
  5. package/docs/generated/builder/README.md +25 -0
  6. package/docs/generated/builder/functions/defineModule.md +60 -0
  7. package/docs/generated/builder/functions/withModuleConfiguration.md +68 -0
  8. package/docs/generated/builder/type-aliases/AnyDefinedModule.md +57 -0
  9. package/docs/generated/builder/type-aliases/ConfiguredDependencies.md +44 -0
  10. package/docs/generated/builder/type-aliases/ConfiguredModule.md +60 -0
  11. package/docs/generated/builder/type-aliases/DefinedModule.md +93 -0
  12. package/docs/generated/builder/type-aliases/DependencyModules.md +29 -0
  13. package/docs/generated/builder/type-aliases/EmptyDependencies.md +34 -0
  14. package/docs/generated/builder/type-aliases/ModuleBuilder.md +124 -0
  15. package/docs/generated/builder/type-aliases/ModuleBuilderProps.md +42 -0
  16. package/docs/generated/builder/type-aliases/ModuleFactoryContext.md +40 -0
  17. package/docs/generated/builder/type-aliases/TablesFromNames.md +28 -0
  18. package/docs/generated/config/README.md +19 -0
  19. package/docs/generated/config/classes/ModuleLoader.md +128 -0
  20. package/docs/generated/config/functions/loadModules.md +79 -0
  21. package/docs/generated/config/sdk/README.md +16 -0
  22. package/docs/generated/config/sdk/functions/getModulesReference.md +81 -0
  23. package/docs/generated/config/sdk/functions/loadModuleForDev.md +53 -0
  24. package/docs/generated/config/sdk/type-aliases/GetModulesReferenceOptions.md +60 -0
  25. package/docs/generated/config/type-aliases/LoadedModules.md +162 -0
  26. package/docs/generated/modules.md +11 -0
  27. package/package.json +17 -18
  28. package/src/builder/helpers.ts +388 -28
  29. package/src/builder/index.ts +8 -1
  30. package/src/builder/register.ts +38 -25
  31. package/src/config/module-loader.ts +251 -21
  32. package/src/config/sdk/dev-context.ts +82 -0
  33. package/src/config/sdk/index.ts +2 -1
  34. package/src/config/sdk/paths.ts +124 -13
  35. package/src/config/sdk/wrapper/base.ts +185 -0
  36. package/src/config/sdk/wrapper/generator.ts +89 -0
  37. package/src/config/sdk/wrapper/strategies.ts +121 -0
  38. package/docs/examples/data-models/core/inventory-module.md +0 -230
  39. package/docs/examples/data-models/core/order-module.md +0 -132
  40. package/docs/examples/data-models/scenarios/inventory-reservation-scenario.md +0 -73
  41. package/docs/examples/data-models/scenarios/multi-storefront-order-scenario.md +0 -99
  42. package/docs/examples/data-models/scenarios/order-payment-status-scenario.md +0 -92
  43. package/docs/examples/data-models/scenarios/procurement-order-scenario.md +0 -95
  44. package/docs/tutorials/creating-modules.md +0 -256
  45. package/src/config/module-registry.ts +0 -22
  46. package/src/stub-loader/index.ts +0 -3
  47. package/src/stub-loader/interface.ts +0 -40
package/README.md CHANGED
@@ -29,31 +29,3 @@ pnpm add @izumisy-tailor/omakase-modules
29
29
 
30
30
  - [Using Modules](./docs/tutorials/using-modules.md) - How to use pre-built modules in your application
31
31
  - [Creating Modules](./docs/tutorials/creating-modules.md) - How to create reusable modules
32
-
33
- ## API Reference
34
-
35
- ### `@izumisy-tailor/omakase-modules`
36
-
37
- - `loadModules(configurator)` - Load and configure modules in your application
38
-
39
- ### `@izumisy-tailor/omakase-modules/builder`
40
-
41
- - `defineModule<Config, Tables>(options)` - Define a new module
42
- - `withModuleConfiguration(module, factory)` - Access module configuration in TailorDB, Resolvers, and Executors
43
- - `ModuleDependency<T>` - Type utility for declaring module dependencies
44
-
45
- ### `@izumisy-tailor/omakase-modules/config/sdk`
46
-
47
- - `getModulesReference(loadedModules)` - Generate file path references for `tailor.config.ts`
48
-
49
- ## Project Structure
50
-
51
- ```
52
- examples/
53
- commerce-core-module/ # E-commerce core module (Product, Customer, etc.)
54
- order-module/ # Order management module
55
- inventory-module/ # Inventory management module
56
- basic-app/ # Application using the above modules
57
- packages/
58
- core/ # omakase-modules core package
59
- ```
@@ -0,0 +1,35 @@
1
+ **@izumisy-tailor/omakase-modules**
2
+
3
+ ***
4
+
5
+ # Omakase Modules
6
+
7
+ A **configurable module system** for Tailor Platform. Define reusable modules with type-safe configurations and share them across applications.
8
+
9
+ ## Motivation
10
+
11
+ When building applications on Tailor Platform, you often face these challenges:
12
+
13
+ 1. **Reusability**: You want to reuse common data models and business logic (e.g., e-commerce, inventory, orders) across multiple applications
14
+ 2. **Customizability**: While modules should be reusable, you need to customize them for application-specific requirements
15
+ 3. **Dependency Management**: Module dependencies should be explicitly defined and managed in a type-safe manner
16
+
17
+ Omakase Modules is designed to solve these challenges by providing a flexible, type-safe module system.
18
+
19
+ ## Key Features
20
+
21
+ - **Module Definition**: Define modules with `defineModule` and declare type-safe configuration schemas
22
+ - **Module Configuration**: Configure modules at the application level, injecting custom attributes and prefixes
23
+ - **Dependency Management**: Explicitly define inter-module dependencies with the `ModuleDependency` type
24
+ - **Configuration Injection**: Inject configurations into TailorDB, Resolvers, and Executors using `withModuleConfiguration`
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pnpm add @izumisy-tailor/omakase-modules
30
+ ```
31
+
32
+ ## Documentation
33
+
34
+ - [Using Modules](_media/using-modules.md) - How to use pre-built modules in your application
35
+ - [Creating Modules](_media/creating-modules.md) - How to create reusable modules
@@ -0,0 +1,471 @@
1
+ # Creating Modules
2
+
3
+ This guide explains how to create reusable Omakase Modules that can be shared across applications.
4
+
5
+ ## Module Structure
6
+
7
+ A typical module package has this structure:
8
+
9
+ ```
10
+ my-module/
11
+ package.json
12
+ tsconfig.json
13
+ src/
14
+ module.ts # Module definition and table types export
15
+ types.ts # Configuration types
16
+ tailordb/
17
+ index.ts # TailorDB exports with tableNames
18
+ my-table.ts # Table builders
19
+ resolvers/
20
+ my-resolver.ts
21
+ executors/
22
+ my-executor.ts
23
+ ```
24
+
25
+ ## Prerequisites: tsconfig.json Path Aliases
26
+
27
+ Your module's `tsconfig.json` must include the following path aliases for the module system to function correctly:
28
+
29
+ ```jsonc
30
+ {
31
+ "compilerOptions": {
32
+ "paths": {
33
+ "@omakase-modules/config": ["./src/module"],
34
+ "@/*": ["./src/*"]
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ | Alias | Path | Purpose |
41
+ |-------|------|---------|
42
+ | `@omakase-modules/config` | `["./src/module"]` | **Required**. Points to your module definition file. The wrapper generator uses this alias to import your module's configuration during code generation. |
43
+ | `@/*` | `["./src/*"]` | **Required**. Provides a shorthand for importing from the `src/` directory. Used internally during development mode to resolve local source files. |
44
+
45
+ ## 1. Define the Module
46
+
47
+ Create the module definition with `defineModule`. The module definition uses a builder pattern:
48
+
49
+ ```typescript
50
+ // src/module.ts
51
+ import {
52
+ defineModule,
53
+ type TablesFromNames,
54
+ } from "@izumisy-tailor/omakase-modules/builder";
55
+ import type { ModuleConfig } from "./types";
56
+ import { tableNames } from "./tailordb";
57
+ import * as pkg from "../package.json";
58
+
59
+ export default defineModule<ModuleConfig, TablesFromNames<typeof tableNames>>({
60
+ packageName: pkg.name,
61
+ })
62
+ .withDevConfig({}) // Optional: default config for development
63
+ .build();
64
+ ```
65
+
66
+ The `packageName` must match the `name` field in your `package.json`. The `TablesFromNames` utility type derives the table types from `tableNames`, ensuring they stay in sync.
67
+
68
+ ### Builder Methods
69
+
70
+ - `.withDevConfig(config)` - Sets the default configuration used during module development
71
+ - `.withDependencies(deps)` - Declares dependencies on other modules (see section 4)
72
+ - `.build()` - Finalizes the module definition (must be called at the end)
73
+
74
+ ## 2. Define Configuration Types
75
+
76
+ Define what configuration options your module accepts:
77
+
78
+ ```typescript
79
+ // src/types.ts
80
+ import { TailorField } from "@tailor-platform/sdk";
81
+
82
+ type DataModelConfiguration = {
83
+ docNumberPrefix?: string;
84
+ customAttributes?: Record<string, TailorField<any>>;
85
+ };
86
+
87
+ export type ModuleConfig = {
88
+ dataModel?: {
89
+ product?: DataModelConfiguration;
90
+ category?: DataModelConfiguration;
91
+ };
92
+ };
93
+ ```
94
+
95
+ ## 3. Build Tables with Configuration
96
+
97
+ Use `withModuleConfiguration` to access configuration when building tables:
98
+
99
+ ```typescript
100
+ // src/tailordb/index.ts
101
+ import {
102
+ withModuleConfiguration,
103
+ type TablesFromNames,
104
+ } from "@izumisy-tailor/omakase-modules/builder";
105
+ import moduleDef from "../module";
106
+ import { buildProductTable } from "./product";
107
+ import { buildCategoryTable } from "./category";
108
+
109
+ /**
110
+ * List of table names exported by this module.
111
+ * This is the single source of truth for table definitions.
112
+ */
113
+ export const tableNames = ["product", "category"] as const;
114
+
115
+ /**
116
+ * Factory function that creates tailordb tables with the given module configuration.
117
+ * This is called by the wrapper files generated by getModulesReference.
118
+ */
119
+ export default withModuleConfiguration(moduleDef, (context) => {
120
+ const category = buildCategoryTable(context);
121
+ const product = buildProductTable(context, { category });
122
+
123
+ return { product, category } satisfies TablesFromNames<typeof tableNames>;
124
+ });
125
+ ```
126
+
127
+ > **Important**: The `tableNames` export is required for the wrapper generator to create named exports for each table.
128
+
129
+ ```typescript
130
+ // src/tailordb/product.ts
131
+ import { type ModuleFactoryContext } from "@izumisy-tailor/omakase-modules/builder";
132
+ import { db, type TailorDBType } from "@tailor-platform/sdk";
133
+ import type { ModuleConfig } from "../types";
134
+
135
+ export const buildProductTable = (
136
+ { config }: ModuleFactoryContext<ModuleConfig>,
137
+ deps: { category: TailorDBType }
138
+ ) => {
139
+ const customAttributes = config.dataModel?.product?.customAttributes || {};
140
+ const docNumberPrefix = config.dataModel?.product?.docNumberPrefix ?? "PROD";
141
+
142
+ return db.type("Product", {
143
+ name: db.string(),
144
+ sku: db.string().unique(),
145
+ categoryId: db.uuid({ optional: true }).relation({
146
+ type: "keyOnly",
147
+ toward: { type: deps.category },
148
+ }),
149
+ docNumber: db.docNumber({ prefix: docNumberPrefix }),
150
+ ...customAttributes,
151
+ ...db.fields.timestamps(),
152
+ });
153
+ };
154
+ ```
155
+
156
+ ## 4. Declare Dependencies on Other Modules
157
+
158
+ If your module depends on other modules, use `.withDependencies()` in your module definition:
159
+
160
+ ```typescript
161
+ // src/module.ts
162
+ import {
163
+ defineModule,
164
+ type TablesFromNames,
165
+ } from "@izumisy-tailor/omakase-modules/builder";
166
+ import { ModuleConfig } from "./types";
167
+ import { tableNames } from "./tailordb";
168
+ import * as pkg from "../package.json";
169
+ import commerceModule from "omakase-module-commerce-core";
170
+ import orderModule from "omakase-module-order";
171
+
172
+ export default defineModule<ModuleConfig, TablesFromNames<typeof tableNames>>({
173
+ packageName: pkg.name,
174
+ })
175
+ .withDevConfig({
176
+ dbNamespace: "main-db",
177
+ })
178
+ .withDependencies({ commerce: commerceModule, order: orderModule })
179
+ .build();
180
+ ```
181
+
182
+ The dependency modules are passed directly to `.withDependencies()`. This ensures type-safe dependency injection when users configure your module.
183
+
184
+ ### Using Dependency Tables in TailorDB
185
+
186
+ When your module needs to reference tables from dependency modules, use `loadedModules.getTables()` in an async factory function:
187
+
188
+ ```typescript
189
+ // src/tailordb/index.ts
190
+ import {
191
+ withModuleConfiguration,
192
+ type TablesFromNames,
193
+ } from "@izumisy-tailor/omakase-modules/builder";
194
+ import moduleDef from "../module";
195
+ import { buildInventoryTable } from "./inventory";
196
+ import { buildInventoryTransactionTable } from "./inventory-transaction";
197
+ import { buildStockAdjustmentTable } from "./stock-adjustment";
198
+ import commerceModuleTables from "omakase-module-commerce-core/backend/tailordb";
199
+ import orderModuleTables from "omakase-module-order/backend/tailordb";
200
+
201
+ export const tableNames = [
202
+ "inventory",
203
+ "inventoryTransaction",
204
+ "stockAdjustment",
205
+ ] as const;
206
+
207
+ export default withModuleConfiguration(
208
+ moduleDef,
209
+ async (context, loadedModules) => {
210
+ // Get tables from dependency modules
211
+ const { product, productVariant } = await loadedModules.getTables(
212
+ commerceModuleTables
213
+ );
214
+ const { order } = await loadedModules.getTables(orderModuleTables);
215
+
216
+ const inventory = buildInventoryTable(context, { product, productVariant });
217
+ const inventoryTransaction = buildInventoryTransactionTable(context, {
218
+ inventory,
219
+ order,
220
+ });
221
+ const stockAdjustment = buildStockAdjustmentTable(context, {
222
+ inventory,
223
+ });
224
+
225
+ return {
226
+ inventory,
227
+ inventoryTransaction,
228
+ stockAdjustment,
229
+ } satisfies TablesFromNames<typeof tableNames>;
230
+ }
231
+ );
232
+ ```
233
+
234
+ ### Using Dependency Tables in Executors
235
+
236
+ Executors can also access dependency tables:
237
+
238
+ ```typescript
239
+ // src/executors/myExecutor.ts
240
+ import { withModuleConfiguration } from "@izumisy-tailor/omakase-modules/builder";
241
+ import { createExecutor, recordCreatedTrigger } from "@tailor-platform/sdk";
242
+ import commerceModuleTables from "omakase-module-commerce-core/backend/tailordb";
243
+ import moduleDef from "../module";
244
+
245
+ export default withModuleConfiguration(
246
+ moduleDef,
247
+ async (_context, loadedModules) => {
248
+ const { productVariant } = await loadedModules.getTables(
249
+ commerceModuleTables
250
+ );
251
+
252
+ return createExecutor({
253
+ name: "my-executor",
254
+ trigger: recordCreatedTrigger({ type: productVariant }),
255
+ operation: { /* ... */ },
256
+ });
257
+ }
258
+ );
259
+ ```
260
+
261
+ ## File Export Requirements
262
+
263
+ Due to Tailor SDK API requirements, **TailorDB** and **Resolvers/Executors** have different export patterns:
264
+
265
+ **TailorDB**: Should use a single `index.ts` barrel export with a `tableNames` constant and a default factory function. This is **strongly recommended** because:
266
+ 1. It allows you to use `satisfies` to verify that all required tables are defined
267
+ 2. The `tableNames` export enables the wrapper generator to create named exports
268
+
269
+ ```typescript
270
+ // src/tailordb/index.ts
271
+ export const tableNames = ["product", "category"] as const;
272
+
273
+ export default withModuleConfiguration(moduleDef, (context) => {
274
+ const category = buildCategoryTable(context);
275
+ const product = buildProductTable(context, { category });
276
+
277
+ // Type error if any required table is missing
278
+ return { product, category } satisfies TablesFromNames<typeof tableNames>;
279
+ });
280
+ ```
281
+
282
+ ```
283
+ src/tailordb/
284
+ index.ts # Exports tableNames and default factory
285
+ product.ts # Table builder (not directly exported)
286
+ category.ts # Table builder (not directly exported)
287
+ ```
288
+
289
+ **Resolvers/Executors**: Must be exported as **separate files**. Each resolver or executor must be in its own file and cannot be barrel-exported from an `index.ts`:
290
+
291
+ ```
292
+ src/resolvers/
293
+ getProduct.ts # Each resolver in its own file
294
+ listProducts.ts
295
+ src/executors/
296
+ onProductCreated.ts # Each executor in its own file
297
+ onOrderPlaced.ts
298
+ ```
299
+
300
+ This is because the Tailor SDK processes resolver and executor files individually, expecting each file to contain a single definition with a default export.
301
+
302
+ ## 5. Set Up tailor.config.ts for Module Development
303
+
304
+ Every module needs a `tailor.config.ts` file for development. This file uses `loadModuleForDev` to resolve the module's factory functions into actual TailorDB table definitions, enabling the Tailor SDK's generator to produce Kysely type definitions.
305
+
306
+ ### Why tailor.config.ts is Required
307
+
308
+ Omakase Modules use a factory pattern—tables are not defined directly but through `withModuleConfiguration` functions that receive configuration at runtime. The Tailor SDK's `@tailor-platform/kysely-type` generator needs concrete table definitions to generate TypeScript types.
309
+
310
+ `loadModuleForDev` bridges this gap by:
311
+ 1. Resolving your module's factory functions with the `devConfig` you defined
312
+ 2. Automatically registering any dependency modules
313
+ 3. Producing actual TailorDB table definitions that the generator can process
314
+
315
+ The generated Kysely types (`src/generated/tailordb.ts`) enable:
316
+ - **Type-safe SQL queries** in your module's executors and resolvers
317
+ - **Cross-module JOIN queries** when other modules depend on yours via the `getDB` function
318
+
319
+ ### Basic tailor.config.ts
320
+
321
+ ```typescript
322
+ // tailor.config.ts
323
+ import { defineConfig, defineGenerators } from "@tailor-platform/sdk";
324
+ import {
325
+ loadModuleForDev,
326
+ getModulesReference,
327
+ } from "@izumisy-tailor/omakase-modules/config/sdk";
328
+ import myModule from "./src/module";
329
+
330
+ const moduleReference = await getModulesReference(
331
+ loadModuleForDev(myModule)
332
+ );
333
+
334
+ export default defineConfig({
335
+ name: "my-module",
336
+
337
+ db: {
338
+ "main-db": {
339
+ files: [...moduleReference.tailordb],
340
+ },
341
+ },
342
+ });
343
+
344
+ export const generators = defineGenerators([
345
+ "@tailor-platform/kysely-type",
346
+ { distPath: "./src/generated/tailordb.ts" },
347
+ ]);
348
+ ```
349
+
350
+ > **Note**: Resolvers and executors are not required in `tailor.config.ts` during module development. The primary purpose is to generate Kysely type definitions for type-safe database queries.
351
+
352
+ ### The Role of devConfig
353
+
354
+ The `devConfig` you define in your module with `.withDevConfig()` is the default configuration used by `loadModuleForDev`. This allows the generator to produce type definitions without explicitly passing configuration each time.
355
+
356
+ If your module doesn't require any configuration, you can omit `.withDevConfig()` entirely—`loadModuleForDev` will use an empty object `{}` as the default.
357
+
358
+ ```typescript
359
+ // src/module.ts - module with configuration
360
+ export default defineModule<ModuleConfig, TablesFromNames<typeof tableNames>>({
361
+ packageName: pkg.name,
362
+ })
363
+ .withDevConfig({
364
+ // Default configuration for development
365
+ dataModel: {
366
+ product: { docNumberPrefix: "DEV" },
367
+ },
368
+ })
369
+ .build();
370
+
371
+ // src/module.ts - module without configuration (withDevConfig can be omitted)
372
+ export default defineModule<ModuleConfig, TablesFromNames<typeof tableNames>>({
373
+ packageName: pkg.name,
374
+ }).build();
375
+ ```
376
+
377
+ When `loadModuleForDev(myModule)` is called without a second argument, it uses this `devConfig` (or `{}` if not defined). You can override it by passing a custom config:
378
+
379
+ ```typescript
380
+ // Use custom config instead of devConfig
381
+ loadModuleForDev(myModule, {
382
+ dataModel: {
383
+ product: { docNumberPrefix: "TEST" },
384
+ },
385
+ });
386
+ ```
387
+
388
+ This flexibility is useful for:
389
+ - **Multiple tailor.config.ts files**: When you need different configurations for different environments (e.g., testing vs development)
390
+ - **Temporary overrides**: When you want to test with a different configuration without modifying `devConfig`
391
+ - **CI/CD pipelines**: When configuration needs to be passed dynamically from environment variables
392
+
393
+ ### Handling Dependencies in Development
394
+
395
+ When your module has dependencies declared with `.withDependencies()`, `loadModuleForDev` automatically registers all dependency modules with empty configurations. This allows the generator to produce types that include dependency tables, enabling JOIN queries across module boundaries.
396
+
397
+ ```typescript
398
+ // Module with dependencies
399
+ export default defineModule<ModuleConfig, TablesFromNames<typeof tableNames>>({
400
+ packageName: pkg.name,
401
+ })
402
+ .withDependencies({ commerce: commerceModule })
403
+ .withDevConfig({ /* ... */ })
404
+ .build();
405
+
406
+ // In tailor.config.ts - dependencies are auto-registered
407
+ const moduleReference = await getModulesReference(
408
+ loadModuleForDev(myModule) // commerceModule is automatically loaded with {}
409
+ );
410
+ ```
411
+
412
+ > **Note**: In development context, dependency modules are registered with empty configurations (`{}`). Actual configuration for dependencies is provided when your module is used in an application via `loadModules`.
413
+
414
+ ## 6. Configure Package Exports
415
+
416
+ Set up your `package.json` to export the module files.
417
+
418
+ > **Important**: The export paths `./backend/tailordb`, `./backend/resolvers/*`, and `./backend/executors/*` are **required** and must not be changed. The module system expects these exact paths to locate module files.
419
+
420
+ ```json
421
+ {
422
+ "name": "my-module",
423
+ "type": "module",
424
+ "exports": {
425
+ ".": "./src/module.ts",
426
+ "./db": "./src/db.ts",
427
+ "./backend/tailordb": "./src/tailordb/index.ts",
428
+ "./backend/resolvers/*": "./src/resolvers/*.ts",
429
+ "./backend/executors/*": "./src/executors/*.ts"
430
+ }
431
+ }
432
+ ```
433
+
434
+ Note that TailorDB uses an `index.ts` barrel export, while resolvers and executors use wildcard patterns to export individual files.
435
+
436
+ > **Design Note**: Modules always export TypeScript source files directly—there is no need to build or bundle them. The Tailor SDK handles TypeScript compilation and bundling as part of its deployment process, so providing raw `.ts` files eliminates unnecessary build steps and keeps the module development workflow simple.
437
+
438
+ ## Best Practices
439
+
440
+ ### Use Factory Functions for Tables
441
+
442
+ Always use factory functions (like `buildProductTable`) instead of directly exporting table definitions. This allows configuration to be injected.
443
+
444
+ ### Type Your Tables
445
+
446
+ Use `satisfies` with `TablesFromNames` to ensure your returned tables match the expected type:
447
+
448
+ ```typescript
449
+ return { product, category } satisfies TablesFromNames<typeof tableNames>;
450
+ ```
451
+
452
+ ### Provide Sensible Defaults
453
+
454
+ Always provide default values for optional configuration:
455
+
456
+ ```typescript
457
+ const prefix = config.dataModel?.product?.docNumberPrefix ?? "PROD";
458
+ ```
459
+
460
+ ## Utility Types Reference
461
+
462
+ The `@izumisy-tailor/omakase-modules/builder` package provides these utility types:
463
+
464
+ | Type | Description |
465
+ |------|-------------|
466
+ | `TablesFromNames<T>` | Derives a tables type from a `tableNames` array. `T` should be `typeof tableNames`. |
467
+ | `ModuleFactoryContext<C>` | Context passed to table builder functions. `C` is your module's config type. |
468
+
469
+ ## Next Steps
470
+
471
+ - See [Using Modules](./using-modules.md) for how applications consume your module
@@ -39,21 +39,25 @@ export default loadModules((loader) => {
39
39
 
40
40
  Each module exposes a `configure()` method that accepts a type-safe configuration object. The available options are defined by the module author.
41
41
 
42
- ## 2. Set Up tsconfig.json
42
+ > **Note**: The `loadModules` function registers all configured modules in a global registry, which is later used by `getModulesReference` to generate wrapper files.
43
43
 
44
- Configure path aliases in `tsconfig.json` to enable module configuration loading:
44
+ ## 2. Configure TypeScript Path Alias
45
45
 
46
- ```json
46
+ You must configure a path alias in your `tsconfig.json` to point to the `modules.ts` file you created above. This alias is required for the generated wrapper files to correctly import your module configuration:
47
+
48
+ ```jsonc
49
+ // tsconfig.json
47
50
  {
48
51
  "compilerOptions": {
52
+ // ... other options
49
53
  "paths": {
50
- "@izumisy-tailor/omakase-modules/config/loader": ["./modules.ts"]
54
+ "@omakase-modules/config": ["./modules"]
51
55
  }
52
56
  }
53
57
  }
54
58
  ```
55
59
 
56
- This tells the module system where to find your configuration file.
60
+ The `@omakase-modules/config` alias should point to your `modules.ts` file (without the `.ts` extension). The wrapper files generated by `getModulesReference` use this alias to import the configured modules.
57
61
 
58
62
  ## 3. Reference Modules in tailor.config.ts
59
63
 
@@ -65,7 +69,7 @@ import { defineConfig } from "@tailor-platform/sdk";
65
69
  import { getModulesReference } from "@izumisy-tailor/omakase-modules/config/sdk";
66
70
  import modules from "./modules";
67
71
 
68
- const moduleReference = getModulesReference(modules);
72
+ const moduleReference = await getModulesReference(modules);
69
73
 
70
74
  export default defineConfig({
71
75
  name: "my-app",
@@ -85,33 +89,51 @@ export default defineConfig({
85
89
  });
86
90
  ```
87
91
 
92
+ `getModulesReference` generates wrapper files in `.tailor-sdk/.omakase` that properly inject module configurations and create named exports for each table. Make sure to add this directory to your `.gitignore`.
93
+
94
+ ### Generated Wrapper Files
95
+
96
+ The wrapper generator creates files that:
97
+ 1. Import the factory function from each module
98
+ 2. Call it with the loaded modules from your `modules.ts`
99
+ 3. Export the results (tables, resolvers, executors) for use by Tailor SDK
100
+
88
101
  ## 4. Handle Module Dependencies
89
102
 
90
- When modules depend on other modules, you need to wire them together:
103
+ When modules depend on other modules, you need to wire them together. The `loader.add()` method returns the configured module, which can then be passed as a dependency to other modules via the `dependencies` property:
91
104
 
92
105
  ```typescript
93
106
  // modules.ts
94
107
  import { loadModules } from "@izumisy-tailor/omakase-modules";
108
+ import { db } from "@tailor-platform/sdk";
95
109
  import ecommerceCoreModule from "omakase-module-commerce-core";
96
110
  import orderModule from "omakase-module-order";
97
111
  import inventoryModule from "omakase-module-inventory";
98
112
 
99
113
  export default loadModules((loader) => {
100
114
  // Add the base module first
101
- const $commerce = loader.add(
115
+ const $ecommerceModule = loader.add(
102
116
  ecommerceCoreModule.configure({
103
- config: { /* ... */ },
117
+ config: {
118
+ dataModel: {
119
+ product: {
120
+ docNumberPrefix: "PP-PROD",
121
+ customAttributes: {
122
+ customStatus: db.enum(["new", "used", "refurbished"]),
123
+ },
124
+ },
125
+ },
126
+ },
104
127
  })
105
128
  );
106
129
 
107
- // Pass the commerce module as a dependency
108
- const $order = loader.add(
130
+ // Pass the commerce module as a dependency via the dependencies property
131
+ const $orderModule = loader.add(
109
132
  orderModule.configure({
110
133
  config: {
111
- dependencies: {
112
- commerce: $commerce,
113
- },
134
+ dataModel: {},
114
135
  },
136
+ dependencies: { commerce: $ecommerceModule },
115
137
  })
116
138
  );
117
139
 
@@ -119,12 +141,10 @@ export default loadModules((loader) => {
119
141
  loader.add(
120
142
  inventoryModule.configure({
121
143
  config: {
122
- dbNamespace: "main",
123
- dependencies: {
124
- commerce: $commerce,
125
- order: $order,
126
- },
144
+ dbNamespace: "main-db",
145
+ invantoryBootstrapBaseValue: 300,
127
146
  },
147
+ dependencies: { commerce: $ecommerceModule, order: $orderModule },
128
148
  })
129
149
  );
130
150
 
@@ -132,7 +152,7 @@ export default loadModules((loader) => {
132
152
  });
133
153
  ```
134
154
 
135
- The `loader.add()` method returns the configured module, which can then be passed as a dependency to other modules.
155
+ Note that dependencies are passed as a separate `dependencies` property alongside `config`, not nested inside `config`. This ensures type-safe dependency wiring.
136
156
 
137
157
  ## Common Configuration Options
138
158
 
@@ -169,6 +189,35 @@ config: {
169
189
  }
170
190
  ```
171
191
 
192
+ ### Module-Specific Options
193
+
194
+ Some modules have their own configuration options:
195
+
196
+ ```typescript
197
+ // Inventory module example
198
+ inventoryModule.configure({
199
+ config: {
200
+ dbNamespace: "main", // Required: TailorDB namespace for this module
201
+ invantoryBootstrapBaseValue: 200, // Module-specific option
202
+ },
203
+ dependencies: { commerce: $ecommerceModule, order: $orderModule },
204
+ })
205
+ ```
206
+
207
+ ## Troubleshooting
208
+
209
+ ### Module Not Found
210
+
211
+ If you see errors about modules not being found, ensure:
212
+ 1. The module is installed as a dependency in your `package.json`
213
+ 2. The module is added via `loader.add()` in your `modules.ts`
214
+
215
+ ### Type Errors with Dependencies
216
+
217
+ If you see type errors when passing dependencies:
218
+ 1. Ensure the dependency module is added before the dependent module
219
+ 2. Use the return value from `loader.add()` as the dependency value
220
+
172
221
  ## Next Steps
173
222
 
174
223
  - See [Creating Modules](./creating-modules.md) if you want to build your own reusable modules