@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.
- package/README.md +0 -28
- package/docs/generated/README.md +35 -0
- package/docs/generated/_media/creating-modules.md +471 -0
- package/docs/{tutorials → generated/_media}/using-modules.md +69 -20
- package/docs/generated/builder/README.md +25 -0
- package/docs/generated/builder/functions/defineModule.md +60 -0
- package/docs/generated/builder/functions/withModuleConfiguration.md +68 -0
- package/docs/generated/builder/type-aliases/AnyDefinedModule.md +57 -0
- package/docs/generated/builder/type-aliases/ConfiguredDependencies.md +44 -0
- package/docs/generated/builder/type-aliases/ConfiguredModule.md +60 -0
- package/docs/generated/builder/type-aliases/DefinedModule.md +93 -0
- package/docs/generated/builder/type-aliases/DependencyModules.md +29 -0
- package/docs/generated/builder/type-aliases/EmptyDependencies.md +34 -0
- package/docs/generated/builder/type-aliases/ModuleBuilder.md +124 -0
- package/docs/generated/builder/type-aliases/ModuleBuilderProps.md +42 -0
- package/docs/generated/builder/type-aliases/ModuleFactoryContext.md +40 -0
- package/docs/generated/builder/type-aliases/TablesFromNames.md +28 -0
- package/docs/generated/config/README.md +19 -0
- package/docs/generated/config/classes/ModuleLoader.md +128 -0
- package/docs/generated/config/functions/loadModules.md +79 -0
- package/docs/generated/config/sdk/README.md +16 -0
- package/docs/generated/config/sdk/functions/getModulesReference.md +81 -0
- package/docs/generated/config/sdk/functions/loadModuleForDev.md +53 -0
- package/docs/generated/config/sdk/type-aliases/GetModulesReferenceOptions.md +60 -0
- package/docs/generated/config/type-aliases/LoadedModules.md +162 -0
- package/docs/generated/modules.md +11 -0
- package/package.json +17 -18
- package/src/builder/helpers.ts +388 -28
- package/src/builder/index.ts +8 -1
- package/src/builder/register.ts +38 -25
- package/src/config/module-loader.ts +251 -21
- package/src/config/sdk/dev-context.ts +82 -0
- package/src/config/sdk/index.ts +2 -1
- package/src/config/sdk/paths.ts +124 -13
- package/src/config/sdk/wrapper/base.ts +185 -0
- package/src/config/sdk/wrapper/generator.ts +89 -0
- package/src/config/sdk/wrapper/strategies.ts +121 -0
- package/docs/examples/data-models/core/inventory-module.md +0 -230
- package/docs/examples/data-models/core/order-module.md +0 -132
- package/docs/examples/data-models/scenarios/inventory-reservation-scenario.md +0 -73
- package/docs/examples/data-models/scenarios/multi-storefront-order-scenario.md +0 -99
- package/docs/examples/data-models/scenarios/order-payment-status-scenario.md +0 -92
- package/docs/examples/data-models/scenarios/procurement-order-scenario.md +0 -95
- package/docs/tutorials/creating-modules.md +0 -256
- package/src/config/module-registry.ts +0 -22
- package/src/stub-loader/index.ts +0 -3
- package/src/stub-loader/interface.ts +0 -40
|
@@ -1,256 +0,0 @@
|
|
|
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
|
|
15
|
-
types.ts # Configuration types
|
|
16
|
-
tailordb/
|
|
17
|
-
index.ts # TailorDB exports
|
|
18
|
-
context.ts # Type definitions for tables
|
|
19
|
-
my-table.ts # Table builders
|
|
20
|
-
resolvers/
|
|
21
|
-
my-resolver.ts
|
|
22
|
-
executors/
|
|
23
|
-
my-executor.ts
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## 1. Define the Module
|
|
27
|
-
|
|
28
|
-
Create the module definition with `defineModule`:
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
// src/module.ts
|
|
32
|
-
import { defineModule } from "@izumisy-tailor/omakase-modules/builder";
|
|
33
|
-
import type { ModuleConfig } from "./types";
|
|
34
|
-
import type { MyModuleTables } from "./tailordb/context";
|
|
35
|
-
import * as pkg from "../package.json";
|
|
36
|
-
|
|
37
|
-
export default defineModule<ModuleConfig, MyModuleTables>({
|
|
38
|
-
packageName: pkg.name,
|
|
39
|
-
});
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
The `packageName` must match the `name` field in your `package.json`.
|
|
43
|
-
|
|
44
|
-
## 2. Define Configuration Types
|
|
45
|
-
|
|
46
|
-
Define what configuration options your module accepts:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
// src/types.ts
|
|
50
|
-
import { TailorField } from "@tailor-platform/sdk";
|
|
51
|
-
|
|
52
|
-
type DataModelConfiguration = {
|
|
53
|
-
docNumberPrefix?: string;
|
|
54
|
-
customAttributes?: Record<string, TailorField<any>>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export type ModuleConfig = {
|
|
58
|
-
dataModel?: {
|
|
59
|
-
product?: DataModelConfiguration;
|
|
60
|
-
category?: DataModelConfiguration;
|
|
61
|
-
};
|
|
62
|
-
};
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## 3. Define Table Types
|
|
66
|
-
|
|
67
|
-
Create type definitions for your module's tables:
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
// src/tailordb/context.ts
|
|
71
|
-
import type { TailorDBType } from "@tailor-platform/sdk";
|
|
72
|
-
import type { ModuleConfig } from "../types";
|
|
73
|
-
|
|
74
|
-
export type MyModuleTables = {
|
|
75
|
-
product: TailorDBType;
|
|
76
|
-
category: TailorDBType;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export type ModuleFactoryContext = {
|
|
80
|
-
config: ModuleConfig;
|
|
81
|
-
};
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## 4. Build Tables with Configuration
|
|
85
|
-
|
|
86
|
-
Use `withModuleConfiguration` to access configuration when building tables:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
// src/tailordb/index.ts
|
|
90
|
-
import { withModuleConfiguration } from "@izumisy-tailor/omakase-modules/builder";
|
|
91
|
-
import type { MyModuleTables } from "./context";
|
|
92
|
-
import moduleDef from "../module";
|
|
93
|
-
import { buildProductTable } from "./product";
|
|
94
|
-
import { buildCategoryTable } from "./category";
|
|
95
|
-
|
|
96
|
-
const tables = await withModuleConfiguration(moduleDef, (context) => {
|
|
97
|
-
const category = buildCategoryTable(context);
|
|
98
|
-
const product = buildProductTable(context, { category });
|
|
99
|
-
|
|
100
|
-
return { product, category } satisfies MyModuleTables;
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
export const productTable = tables.product;
|
|
104
|
-
export const categoryTable = tables.category;
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
// src/tailordb/product.ts
|
|
109
|
-
import { db } from "@tailor-platform/sdk";
|
|
110
|
-
import type { ModuleFactoryContext } from "./context";
|
|
111
|
-
|
|
112
|
-
export const buildProductTable = (
|
|
113
|
-
{ config }: ModuleFactoryContext,
|
|
114
|
-
deps: { category: TailorDBType }
|
|
115
|
-
) => {
|
|
116
|
-
const customAttributes = config.dataModel?.product?.customAttributes || {};
|
|
117
|
-
const docNumberPrefix = config.dataModel?.product?.docNumberPrefix ?? "PROD";
|
|
118
|
-
|
|
119
|
-
return db.type("Product", {
|
|
120
|
-
name: db.string(),
|
|
121
|
-
sku: db.string().unique(),
|
|
122
|
-
categoryId: db.uuid({ optional: true }).relation({
|
|
123
|
-
type: "keyOnly",
|
|
124
|
-
toward: { type: deps.category },
|
|
125
|
-
}),
|
|
126
|
-
docNumber: db.docNumber({ prefix: docNumberPrefix }),
|
|
127
|
-
...customAttributes,
|
|
128
|
-
...db.fields.timestamps(),
|
|
129
|
-
});
|
|
130
|
-
};
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## 5. Declare Dependencies on Other Modules
|
|
134
|
-
|
|
135
|
-
If your module depends on other modules, use `ModuleDependency`:
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// src/types.ts
|
|
139
|
-
import type { ModuleDependency } from "@izumisy-tailor/omakase-modules/builder";
|
|
140
|
-
import type commerceCoreModule from "omakase-module-commerce-core";
|
|
141
|
-
|
|
142
|
-
export type ModuleConfig = {
|
|
143
|
-
dataModel?: { /* ... */ };
|
|
144
|
-
dependencies: {
|
|
145
|
-
commerce: ModuleDependency<typeof commerceCoreModule>;
|
|
146
|
-
};
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
This ensures type-safe dependency injection when users configure your module.
|
|
151
|
-
|
|
152
|
-
## File Export Requirements
|
|
153
|
-
|
|
154
|
-
Due to Tailor SDK API requirements, **TailorDB** and **Resolvers/Executors** have different export patterns:
|
|
155
|
-
|
|
156
|
-
**TailorDB**: Should use a single `index.ts` barrel export. All table definitions should be exported from one file. This is **strongly recommended** because it allows you to use `satisfies` to verify that all required tables are defined for the module:
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
// src/tailordb/index.ts
|
|
160
|
-
const tables = await withModuleConfiguration(moduleDef, (context) => {
|
|
161
|
-
const category = buildCategoryTable(context);
|
|
162
|
-
const product = buildProductTable(context, { category });
|
|
163
|
-
|
|
164
|
-
// Type error if any required table is missing
|
|
165
|
-
return { product, category } satisfies MyModuleTables;
|
|
166
|
-
});
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
```
|
|
170
|
-
src/tailordb/
|
|
171
|
-
index.ts # Exports all tables
|
|
172
|
-
product.ts # Table builder (not directly exported)
|
|
173
|
-
category.ts # Table builder (not directly exported)
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**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`:
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
src/resolvers/
|
|
180
|
-
getProduct.ts # Each resolver in its own file
|
|
181
|
-
listProducts.ts
|
|
182
|
-
src/executors/
|
|
183
|
-
onProductCreated.ts # Each executor in its own file
|
|
184
|
-
onOrderPlaced.ts
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
This is because the Tailor SDK processes resolver and executor files individually, expecting each file to contain a single definition with a default export.
|
|
188
|
-
|
|
189
|
-
## 6. Configure Package Exports
|
|
190
|
-
|
|
191
|
-
Set up your `package.json` to export the built files.
|
|
192
|
-
|
|
193
|
-
> **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.
|
|
194
|
-
|
|
195
|
-
```json
|
|
196
|
-
{
|
|
197
|
-
"name": "my-module",
|
|
198
|
-
"type": "module",
|
|
199
|
-
"exports": {
|
|
200
|
-
".": {
|
|
201
|
-
"default": "./dist/module.mjs",
|
|
202
|
-
"types": "./dist/module.d.mts"
|
|
203
|
-
},
|
|
204
|
-
"./backend/tailordb": {
|
|
205
|
-
"default": "./dist/tailordb/index.mjs",
|
|
206
|
-
"types": "./dist/tailordb/index.d.mts"
|
|
207
|
-
},
|
|
208
|
-
"./backend/resolvers/*": {
|
|
209
|
-
"default": "./dist/resolvers/*.mjs",
|
|
210
|
-
"types": "./dist/resolvers/*.d.mts"
|
|
211
|
-
},
|
|
212
|
-
"./backend/executors/*": {
|
|
213
|
-
"default": "./dist/executors/*.mjs",
|
|
214
|
-
"types": "./dist/executors/*.d.mts"
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Note that TailorDB uses an `index.mjs` barrel export, while resolvers and executors use wildcard patterns to export individual files.
|
|
221
|
-
|
|
222
|
-
## Best Practices
|
|
223
|
-
|
|
224
|
-
### Use Factory Functions for Tables
|
|
225
|
-
|
|
226
|
-
Always use factory functions (like `buildProductTable`) instead of directly exporting table definitions. This allows configuration to be injected.
|
|
227
|
-
|
|
228
|
-
### Type Your Tables
|
|
229
|
-
|
|
230
|
-
Use `satisfies` to ensure your returned tables match the expected type:
|
|
231
|
-
|
|
232
|
-
```typescript
|
|
233
|
-
return { product, category } satisfies MyModuleTables;
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Provide Sensible Defaults
|
|
237
|
-
|
|
238
|
-
Always provide default values for optional configuration:
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
const prefix = config.dataModel?.product?.docNumberPrefix ?? "PROD";
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Export Table References
|
|
245
|
-
|
|
246
|
-
Export individual table references for use in other modules:
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
export const productTable = tables.product;
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
This allows other modules to reference your tables in relations and executors.
|
|
253
|
-
|
|
254
|
-
## Next Steps
|
|
255
|
-
|
|
256
|
-
- See [Using Modules](./using-modules.md) for how applications consume your module
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { ConfiguredModule } from "../builder/helpers";
|
|
2
|
-
|
|
3
|
-
const registry = new Map<string, ConfiguredModule<any>>();
|
|
4
|
-
|
|
5
|
-
export const clearModuleRegistry = () => {
|
|
6
|
-
registry.clear();
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const registerConfiguredModules = (
|
|
10
|
-
modules: ReadonlyArray<ConfiguredModule<any>>
|
|
11
|
-
) => {
|
|
12
|
-
modules.forEach((module) => {
|
|
13
|
-
registry.set(module.packageName, module);
|
|
14
|
-
});
|
|
15
|
-
return modules;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const getConfiguredModule = <C extends Record<string, unknown>>(
|
|
19
|
-
packageName: string
|
|
20
|
-
): ConfiguredModule<C> | undefined => {
|
|
21
|
-
return registry.get(packageName) as ConfiguredModule<C> | undefined;
|
|
22
|
-
};
|
package/src/stub-loader/index.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { DefinedModule } from "../builder";
|
|
2
|
-
|
|
3
|
-
export type ModuleConfigLoaderReturn<C extends Record<string, unknown>> =
|
|
4
|
-
Promise<{
|
|
5
|
-
config: C;
|
|
6
|
-
}>;
|
|
7
|
-
|
|
8
|
-
const loadConfig = async <C extends Record<string, unknown>>(
|
|
9
|
-
_: DefinedModule<C, any>
|
|
10
|
-
): ModuleConfigLoaderReturn<C> => {
|
|
11
|
-
console.warn(
|
|
12
|
-
`[warn] Empty module configuration loaded. Override "@izumisy-tailor/omakase-modules/config/loader" to "./modules.ts" in tsconfig.json paths in your app`
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
config: {} as C,
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* `moduleConfigLoader` is an interface for loading module configurations.
|
|
22
|
-
*
|
|
23
|
-
* By default, it throws an error indicating that the loader needs to be overridden in tsconfig.json.
|
|
24
|
-
* Users should provide their "modules.ts" that calls `loadModules` which implements the actual loading logic.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```
|
|
28
|
-
* {
|
|
29
|
-
* "compilerOptions": {
|
|
30
|
-
* // ...
|
|
31
|
-
* "paths": {
|
|
32
|
-
* "@izumisy-tailor/omakase-modules/config/loader": ["./modules.ts"],
|
|
33
|
-
* }
|
|
34
|
-
* }
|
|
35
|
-
* }
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export const moduleConfigLoader = {
|
|
39
|
-
loadConfig,
|
|
40
|
-
};
|