@omnifyjp/omnify 3.14.1 → 3.15.1
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/package.json +6 -6
- package/ts-dist/cli.js +10 -1
- package/ts-dist/generator.d.ts +9 -1
- package/ts-dist/generator.js +12 -4
- package/ts-dist/index.d.ts +1 -1
- package/ts-dist/php/schema-reader.d.ts +3 -1
- package/ts-dist/php/schema-reader.js +5 -1
- package/ts-dist/rn-query-setup-generator.d.ts +20 -0
- package/ts-dist/rn-query-setup-generator.js +154 -0
- package/ts-dist/types.d.ts +11 -0
- package/types/config.d.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnifyjp/omnify",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.1",
|
|
4
4
|
"description": "Schema-driven code generation for Laravel, TypeScript, and SQL",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"zod": "^3.24.0"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@omnifyjp/omnify-darwin-arm64": "3.
|
|
40
|
-
"@omnifyjp/omnify-darwin-x64": "3.
|
|
41
|
-
"@omnifyjp/omnify-linux-x64": "3.
|
|
42
|
-
"@omnifyjp/omnify-linux-arm64": "3.
|
|
43
|
-
"@omnifyjp/omnify-win32-x64": "3.
|
|
39
|
+
"@omnifyjp/omnify-darwin-arm64": "3.15.1",
|
|
40
|
+
"@omnifyjp/omnify-darwin-x64": "3.15.1",
|
|
41
|
+
"@omnifyjp/omnify-linux-x64": "3.15.1",
|
|
42
|
+
"@omnifyjp/omnify-linux-arm64": "3.15.1",
|
|
43
|
+
"@omnifyjp/omnify-win32-x64": "3.15.1"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/ts-dist/cli.js
CHANGED
|
@@ -102,6 +102,8 @@ function resolveFromConfig(configPath) {
|
|
|
102
102
|
inputSpec,
|
|
103
103
|
tsEnabled,
|
|
104
104
|
tsOutput,
|
|
105
|
+
tsPlatform: tsConfig?.platform,
|
|
106
|
+
tsAuth: tsConfig?.auth,
|
|
105
107
|
laravelEnabled,
|
|
106
108
|
laravelOverrides,
|
|
107
109
|
};
|
|
@@ -120,6 +122,8 @@ program
|
|
|
120
122
|
let inputSpec;
|
|
121
123
|
let tsEnabled = true;
|
|
122
124
|
let tsOutput;
|
|
125
|
+
let tsPlatform;
|
|
126
|
+
let tsAuth;
|
|
123
127
|
let laravelEnabled = false;
|
|
124
128
|
let laravelOverrides;
|
|
125
129
|
let configDir = process.cwd();
|
|
@@ -142,6 +146,8 @@ program
|
|
|
142
146
|
inputSpec = opts.input ?? resolved.inputSpec;
|
|
143
147
|
tsEnabled = resolved.tsEnabled;
|
|
144
148
|
tsOutput = opts.output ? resolve(opts.output) : resolved.tsOutput;
|
|
149
|
+
tsPlatform = resolved.tsPlatform;
|
|
150
|
+
tsAuth = resolved.tsAuth;
|
|
145
151
|
laravelEnabled = resolved.laravelEnabled;
|
|
146
152
|
laravelOverrides = resolved.laravelOverrides;
|
|
147
153
|
}
|
|
@@ -166,7 +172,10 @@ program
|
|
|
166
172
|
// ---- TypeScript generation ----
|
|
167
173
|
if (tsEnabled && tsOutput) {
|
|
168
174
|
console.log(`\n[TypeScript] Output: ${tsOutput}`);
|
|
169
|
-
const files = generateTypeScript(input
|
|
175
|
+
const files = generateTypeScript(input, {
|
|
176
|
+
platform: tsPlatform,
|
|
177
|
+
auth: tsAuth,
|
|
178
|
+
});
|
|
170
179
|
mkdirSync(join(tsOutput, 'base'), { recursive: true });
|
|
171
180
|
mkdirSync(join(tsOutput, 'enum'), { recursive: true });
|
|
172
181
|
let tsCreated = 0;
|
package/ts-dist/generator.d.ts
CHANGED
|
@@ -13,7 +13,15 @@
|
|
|
13
13
|
* index.ts — Re-exports (always overwritten)
|
|
14
14
|
*/
|
|
15
15
|
import type { SchemasJson, TypeScriptFile } from './types.js';
|
|
16
|
+
/** Build GeneratorOptions from schemas.json. */
|
|
17
|
+
/** Extra config that the CLI resolves from omnify.yaml's codegen.typescript section. */
|
|
18
|
+
export interface GenerateExtraConfig {
|
|
19
|
+
platform?: 'web' | 'expo';
|
|
20
|
+
auth?: 'cookie' | 'secureStore';
|
|
21
|
+
}
|
|
16
22
|
/**
|
|
17
23
|
* Generate all TypeScript files from schemas.json input.
|
|
24
|
+
*
|
|
25
|
+
* @param extra - Platform/auth config resolved from omnify.yaml's codegen.typescript section (issue #63).
|
|
18
26
|
*/
|
|
19
|
-
export declare function generateTypeScript(input: SchemasJson): TypeScriptFile[];
|
|
27
|
+
export declare function generateTypeScript(input: SchemasJson, extra?: GenerateExtraConfig): TypeScriptFile[];
|
package/ts-dist/generator.js
CHANGED
|
@@ -21,6 +21,7 @@ import { generateTsServices } from './ts-service-generator.js';
|
|
|
21
21
|
import { generateTsQueryKeys } from './ts-query-keys-generator.js';
|
|
22
22
|
import { generateTsHooks } from './ts-hooks-generator.js';
|
|
23
23
|
import { buildFormShape, formatPayloadBuilderSection, } from './payload-builder-generator.js';
|
|
24
|
+
import { generateRnQuerySetup } from './rn-query-setup-generator.js';
|
|
24
25
|
/** Auto-generated file header. */
|
|
25
26
|
function generateBaseHeader() {
|
|
26
27
|
return `/**
|
|
@@ -33,13 +34,14 @@ function generateBaseHeader() {
|
|
|
33
34
|
|
|
34
35
|
`;
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
-
function buildOptions(input) {
|
|
37
|
+
function buildOptions(input, extra) {
|
|
38
38
|
return {
|
|
39
39
|
locales: input.locale.locales,
|
|
40
40
|
defaultLocale: input.locale.defaultLocale,
|
|
41
41
|
fallbackLocale: input.locale.fallbackLocale,
|
|
42
42
|
customTypes: input.customTypes,
|
|
43
|
+
platform: extra?.platform,
|
|
44
|
+
auth: extra?.auth,
|
|
43
45
|
};
|
|
44
46
|
}
|
|
45
47
|
/** Generate a base interface file for a schema. */
|
|
@@ -437,9 +439,11 @@ function validateSchemaNames(schemas) {
|
|
|
437
439
|
}
|
|
438
440
|
/**
|
|
439
441
|
* Generate all TypeScript files from schemas.json input.
|
|
442
|
+
*
|
|
443
|
+
* @param extra - Platform/auth config resolved from omnify.yaml's codegen.typescript section (issue #63).
|
|
440
444
|
*/
|
|
441
|
-
export function generateTypeScript(input) {
|
|
442
|
-
const options = buildOptions(input);
|
|
445
|
+
export function generateTypeScript(input, extra) {
|
|
446
|
+
const options = buildOptions(input, extra);
|
|
443
447
|
const schemas = input.schemas;
|
|
444
448
|
// Validate no reserved name collisions
|
|
445
449
|
validateSchemaNames(schemas);
|
|
@@ -501,6 +505,10 @@ export function generateTypeScript(input) {
|
|
|
501
505
|
files.push(...generateTsServices(schemas, options));
|
|
502
506
|
files.push(...generateTsQueryKeys(schemas));
|
|
503
507
|
files.push(...generateTsHooks(schemas));
|
|
508
|
+
// React Native / Expo query setup (issue #63)
|
|
509
|
+
if (options.platform === 'expo') {
|
|
510
|
+
files.push(generateRnQuerySetup(options.auth ?? 'secureStore'));
|
|
511
|
+
}
|
|
504
512
|
// Index re-exports
|
|
505
513
|
files.push(generateIndexFile(schemas, schemaEnums, pluginEnums, inlineTypeAliases, hasFiles));
|
|
506
514
|
return files;
|
package/ts-dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* TypeScript model type generator from Omnify schemas.json.
|
|
5
5
|
*/
|
|
6
|
-
export { generateTypeScript } from './generator.js';
|
|
6
|
+
export { generateTypeScript, type GenerateExtraConfig } from './generator.js';
|
|
7
7
|
export type { SchemasJson, SchemaDefinition, PropertyDefinition, TypeScriptFile, TSInterface, TSProperty, TSEnum, TSEnumValue, TSTypeAlias, GeneratorOptions, LocalizedString, LocaleMap, } from './types.js';
|
|
8
8
|
export { schemaToInterface, formatInterface, formatProperty, generateInterfaces, getPropertyType, toSnakeCase, } from './interface-generator.js';
|
|
9
9
|
export { generateEnums, generatePluginEnums, formatEnum, formatTypeAlias, extractInlineEnums, toPascalCase, toEnumMemberName, } from './enum-generator.js';
|
|
@@ -51,7 +51,9 @@ export declare class SchemaReader {
|
|
|
51
51
|
getSchemasWithApi(): Record<string, SchemaDefinition>;
|
|
52
52
|
/** Check if any schema has api options. */
|
|
53
53
|
hasApiSchemas(): boolean;
|
|
54
|
-
/** Check if any schema has File-type properties
|
|
54
|
+
/** Check if any schema has File-type properties OR the project has
|
|
55
|
+
* `file:` config (issue #64: generate File infrastructure even when
|
|
56
|
+
* no schema declares `type: File` yet). */
|
|
55
57
|
hasFileProperties(): boolean;
|
|
56
58
|
/** Get the file config from schemas.json. */
|
|
57
59
|
getFileConfig(): import("../types.js").FileConfigExport | null;
|
|
@@ -172,8 +172,12 @@ export class SchemaReader {
|
|
|
172
172
|
hasApiSchemas() {
|
|
173
173
|
return Object.keys(this.getSchemasWithApi()).length > 0;
|
|
174
174
|
}
|
|
175
|
-
/** Check if any schema has File-type properties
|
|
175
|
+
/** Check if any schema has File-type properties OR the project has
|
|
176
|
+
* `file:` config (issue #64: generate File infrastructure even when
|
|
177
|
+
* no schema declares `type: File` yet). */
|
|
176
178
|
hasFileProperties() {
|
|
179
|
+
if (this.data.fileConfig)
|
|
180
|
+
return true;
|
|
177
181
|
for (const schema of Object.values(this.getObjectSchemas())) {
|
|
178
182
|
const props = schema.properties ?? {};
|
|
179
183
|
for (const prop of Object.values(props)) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — React Native Query Setup Generator (issue #63)
|
|
3
|
+
*
|
|
4
|
+
* When the codegen target has `platform: 'expo'`, this module generates a
|
|
5
|
+
* `rn-query-setup.ts` utility file at the output root. The file wires up
|
|
6
|
+
* TanStack Query's `focusManager` and `onlineManager` for React Native so
|
|
7
|
+
* queries auto-refetch when the app comes back from the background and
|
|
8
|
+
* pause when the device is offline.
|
|
9
|
+
*
|
|
10
|
+
* The file also exports an `apiFetch` wrapper that reads the bearer token
|
|
11
|
+
* from Expo SecureStore (async) and injects it into every request. This
|
|
12
|
+
* replaces the browser-cookie auth path used by web targets.
|
|
13
|
+
*/
|
|
14
|
+
import type { TypeScriptFile } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Generate `rn-query-setup.ts` for Expo / React Native targets.
|
|
17
|
+
*
|
|
18
|
+
* @param auth - Auth strategy: 'secureStore' (default for expo) or 'cookie'
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateRnQuerySetup(auth?: string): TypeScriptFile;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — React Native Query Setup Generator (issue #63)
|
|
3
|
+
*
|
|
4
|
+
* When the codegen target has `platform: 'expo'`, this module generates a
|
|
5
|
+
* `rn-query-setup.ts` utility file at the output root. The file wires up
|
|
6
|
+
* TanStack Query's `focusManager` and `onlineManager` for React Native so
|
|
7
|
+
* queries auto-refetch when the app comes back from the background and
|
|
8
|
+
* pause when the device is offline.
|
|
9
|
+
*
|
|
10
|
+
* The file also exports an `apiFetch` wrapper that reads the bearer token
|
|
11
|
+
* from Expo SecureStore (async) and injects it into every request. This
|
|
12
|
+
* replaces the browser-cookie auth path used by web targets.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Generate `rn-query-setup.ts` for Expo / React Native targets.
|
|
16
|
+
*
|
|
17
|
+
* @param auth - Auth strategy: 'secureStore' (default for expo) or 'cookie'
|
|
18
|
+
*/
|
|
19
|
+
export function generateRnQuerySetup(auth = 'secureStore') {
|
|
20
|
+
const authImport = auth === 'secureStore'
|
|
21
|
+
? `import * as SecureStore from 'expo-secure-store';`
|
|
22
|
+
: '';
|
|
23
|
+
const authHeaders = auth === 'secureStore'
|
|
24
|
+
? `
|
|
25
|
+
/**
|
|
26
|
+
* Read the bearer token from Expo SecureStore (async) and return the
|
|
27
|
+
* Authorization header. Returns an empty object when no token is stored.
|
|
28
|
+
*/
|
|
29
|
+
async function getAuthHeaders(): Promise<Record<string, string>> {
|
|
30
|
+
const token = await SecureStore.getItemAsync('auth_token');
|
|
31
|
+
return token ? { Authorization: \`Bearer \${token}\` } : {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Authenticated fetch wrapper for React Native. Injects the bearer token
|
|
36
|
+
* from SecureStore into every request. Use this as the \`apiFetch\`
|
|
37
|
+
* parameter when creating service factories.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const zoneService = createZoneBaseService((path) => \`\${BASE_URL}/zones\${path}\`);
|
|
41
|
+
* // In the app, wrap with apiFetch from this module.
|
|
42
|
+
*/
|
|
43
|
+
export async function apiFetch<T>(url: string, init?: RequestInit): Promise<T> {
|
|
44
|
+
const headers = {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
'Accept': 'application/json',
|
|
47
|
+
...await getAuthHeaders(),
|
|
48
|
+
...init?.headers,
|
|
49
|
+
};
|
|
50
|
+
const res = await fetch(url, { ...init, headers });
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
const body = await res.text().catch(() => '');
|
|
53
|
+
throw new Error(body || \`HTTP \${res.status}\`);
|
|
54
|
+
}
|
|
55
|
+
return res.json();
|
|
56
|
+
}
|
|
57
|
+
`
|
|
58
|
+
: `
|
|
59
|
+
/**
|
|
60
|
+
* Basic fetch wrapper (cookie auth). Same as the web target's user-land
|
|
61
|
+
* apiFetch — provided here so the generated service files can import from
|
|
62
|
+
* a consistent location.
|
|
63
|
+
*/
|
|
64
|
+
export async function apiFetch<T>(url: string, init?: RequestInit): Promise<T> {
|
|
65
|
+
const headers = {
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
'Accept': 'application/json',
|
|
68
|
+
...init?.headers,
|
|
69
|
+
};
|
|
70
|
+
const res = await fetch(url, { ...init, headers, credentials: 'include' });
|
|
71
|
+
if (!res.ok) {
|
|
72
|
+
const body = await res.text().catch(() => '');
|
|
73
|
+
throw new Error(body || \`HTTP \${res.status}\`);
|
|
74
|
+
}
|
|
75
|
+
return res.json();
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
const content = `/**
|
|
79
|
+
* DO NOT EDIT - Auto-generated by Omnify.
|
|
80
|
+
*
|
|
81
|
+
* React Native / Expo query setup. Wire this up in your app's entry point
|
|
82
|
+
* (e.g. \`app/_layout.tsx\`) to enable:
|
|
83
|
+
* - Auto-refetch when the app returns from background (AppState)
|
|
84
|
+
* - Pause queries when offline (NetInfo)
|
|
85
|
+
* - Authenticated fetch with bearer token from SecureStore
|
|
86
|
+
*
|
|
87
|
+
* @generated by omnify (issue #63)
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
import { AppState, type AppStateStatus } from 'react-native';
|
|
91
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
92
|
+
import {
|
|
93
|
+
focusManager,
|
|
94
|
+
onlineManager,
|
|
95
|
+
QueryClient,
|
|
96
|
+
} from '@tanstack/react-query';
|
|
97
|
+
${authImport}
|
|
98
|
+
|
|
99
|
+
// ---- Focus Manager (refetch on app foreground) ----
|
|
100
|
+
|
|
101
|
+
function onAppStateChange(status: AppStateStatus) {
|
|
102
|
+
focusManager.setFocused(status === 'active');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Call once at app startup to wire AppState → TanStack Query focusManager.
|
|
107
|
+
* When the user switches back to the app, all stale queries refetch.
|
|
108
|
+
*/
|
|
109
|
+
export function setupFocusManager(): () => void {
|
|
110
|
+
const sub = AppState.addEventListener('change', onAppStateChange);
|
|
111
|
+
return () => sub.remove();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ---- Online Manager (pause queries when offline) ----
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Call once at app startup to wire NetInfo → TanStack Query onlineManager.
|
|
118
|
+
* Queries pause when the device loses connectivity and resume when it's back.
|
|
119
|
+
*/
|
|
120
|
+
export function setupOnlineManager(): () => void {
|
|
121
|
+
return onlineManager.setEventListener((setOnline) => {
|
|
122
|
+
return NetInfo.addEventListener((state) => {
|
|
123
|
+
setOnline(!!state.isConnected);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---- Query Client factory ----
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Pre-configured QueryClient for React Native with sensible defaults:
|
|
132
|
+
* - \`refetchOnWindowFocus\` wired via focusManager above
|
|
133
|
+
* - \`retry: 2\` for flaky mobile networks
|
|
134
|
+
* - \`staleTime: 30s\` to reduce unnecessary refetches on tab switch
|
|
135
|
+
*/
|
|
136
|
+
export function createRnQueryClient(): QueryClient {
|
|
137
|
+
return new QueryClient({
|
|
138
|
+
defaultOptions: {
|
|
139
|
+
queries: {
|
|
140
|
+
retry: 2,
|
|
141
|
+
staleTime: 30_000,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
${authHeaders}
|
|
147
|
+
`;
|
|
148
|
+
return {
|
|
149
|
+
filePath: 'rn-query-setup.ts',
|
|
150
|
+
content,
|
|
151
|
+
types: ['setupFocusManager', 'setupOnlineManager', 'createRnQueryClient', 'apiFetch'],
|
|
152
|
+
overwrite: true,
|
|
153
|
+
};
|
|
154
|
+
}
|
package/ts-dist/types.d.ts
CHANGED
|
@@ -51,6 +51,10 @@ export interface SchemasJson {
|
|
|
51
51
|
export interface PackageExportInfo {
|
|
52
52
|
readonly migrationsPath?: string;
|
|
53
53
|
readonly codegen?: PackageCodegenExport;
|
|
54
|
+
/** Schema name → consumer FQCN mapping for relation resolution. Issue #61. */
|
|
55
|
+
readonly modelMap?: Record<string, string>;
|
|
56
|
+
/** Whether this package's models are MappedSuperclass (abstract). Issue #61. */
|
|
57
|
+
readonly abstract?: boolean;
|
|
54
58
|
}
|
|
55
59
|
/** Codegen namespace info from a package. */
|
|
56
60
|
export interface PackageCodegenExport {
|
|
@@ -254,6 +258,9 @@ export interface PropertyDefinition {
|
|
|
254
258
|
readonly mappedBy?: string;
|
|
255
259
|
readonly orderBy?: readonly OrderByItem[];
|
|
256
260
|
readonly useCurrent?: boolean;
|
|
261
|
+
readonly deprecated?: boolean;
|
|
262
|
+
readonly deprecatedSince?: string;
|
|
263
|
+
readonly removalTarget?: string;
|
|
257
264
|
readonly searchable?: boolean;
|
|
258
265
|
readonly filterable?: boolean;
|
|
259
266
|
readonly sortable?: boolean;
|
|
@@ -347,4 +354,8 @@ export interface GeneratorOptions {
|
|
|
347
354
|
readonly defaultLocale: string;
|
|
348
355
|
readonly fallbackLocale: string;
|
|
349
356
|
readonly customTypes: SchemasJson['customTypes'];
|
|
357
|
+
/** Target platform: 'web' (default) or 'expo' (React Native). Issue #63. */
|
|
358
|
+
readonly platform?: 'web' | 'expo';
|
|
359
|
+
/** Auth strategy: 'cookie' (default) or 'secureStore' (Expo). Issue #63. */
|
|
360
|
+
readonly auth?: 'cookie' | 'secureStore';
|
|
350
361
|
}
|
package/types/config.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface MigrationConfig {
|
|
|
19
19
|
schemasPath?: string;
|
|
20
20
|
/** SQL dialect for generated migrations (sql only). */
|
|
21
21
|
dialect?: SQLDialect;
|
|
22
|
+
/** Use deterministic timestamps (year-2000 base + sort-order offset) for packages. Issue #60. */
|
|
23
|
+
stableTimestamps?: boolean;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/** Per-connection database and migration configuration. */
|
|
@@ -135,6 +137,8 @@ export interface OmnifyConfig {
|
|
|
135
137
|
compoundTypes?: string[];
|
|
136
138
|
/** Code generation configuration (connection-independent). */
|
|
137
139
|
codegen?: CodegenConfig;
|
|
140
|
+
/** Package mode: stable deterministic timestamps for all Laravel migrations. Issue #60. */
|
|
141
|
+
package?: boolean;
|
|
138
142
|
/** Enable verbose output during generation. */
|
|
139
143
|
verbose?: boolean;
|
|
140
144
|
}
|