@wp-typia/project-tools 0.22.9 → 0.23.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 (90) hide show
  1. package/dist/runtime/ai-artifacts.js +3 -4
  2. package/dist/runtime/ai-feature-artifacts.js +2 -4
  3. package/dist/runtime/cli-add-collision.d.ts +25 -0
  4. package/dist/runtime/cli-add-collision.js +76 -0
  5. package/dist/runtime/cli-add-filesystem.js +2 -15
  6. package/dist/runtime/cli-add-help.js +11 -2
  7. package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
  8. package/dist/runtime/cli-add-kind-ids.js +3 -0
  9. package/dist/runtime/cli-add-types.d.ts +117 -0
  10. package/dist/runtime/cli-add-types.js +29 -1
  11. package/dist/runtime/cli-add-validation.d.ts +90 -1
  12. package/dist/runtime/cli-add-validation.js +304 -1
  13. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +74 -19
  14. package/dist/runtime/cli-add-workspace-admin-view-source.js +11 -2
  15. package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +20 -2
  16. package/dist/runtime/cli-add-workspace-admin-view-templates.js +359 -3
  17. package/dist/runtime/cli-add-workspace-admin-view-types.d.ts +21 -0
  18. package/dist/runtime/cli-add-workspace-admin-view-types.js +22 -0
  19. package/dist/runtime/cli-add-workspace-ai-anchors.js +121 -31
  20. package/dist/runtime/cli-add-workspace-contract-source-emitters.d.ts +15 -0
  21. package/dist/runtime/cli-add-workspace-contract-source-emitters.js +42 -0
  22. package/dist/runtime/cli-add-workspace-contract.d.ts +15 -0
  23. package/dist/runtime/cli-add-workspace-contract.js +65 -0
  24. package/dist/runtime/cli-add-workspace-integration-env.d.ts +24 -0
  25. package/dist/runtime/cli-add-workspace-integration-env.js +391 -0
  26. package/dist/runtime/cli-add-workspace-post-meta-anchors.d.ts +23 -0
  27. package/dist/runtime/cli-add-workspace-post-meta-anchors.js +244 -0
  28. package/dist/runtime/cli-add-workspace-post-meta-source-emitters.d.ts +63 -0
  29. package/dist/runtime/cli-add-workspace-post-meta-source-emitters.js +179 -0
  30. package/dist/runtime/cli-add-workspace-post-meta.d.ts +15 -0
  31. package/dist/runtime/cli-add-workspace-post-meta.js +107 -0
  32. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +1 -0
  33. package/dist/runtime/cli-add-workspace-rest-anchors.js +285 -21
  34. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +90 -2
  35. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +302 -29
  36. package/dist/runtime/cli-add-workspace-rest.d.ts +15 -2
  37. package/dist/runtime/cli-add-workspace-rest.js +329 -21
  38. package/dist/runtime/cli-add-workspace.d.ts +15 -0
  39. package/dist/runtime/cli-add-workspace.js +15 -0
  40. package/dist/runtime/cli-add.d.ts +1 -1
  41. package/dist/runtime/cli-add.js +1 -1
  42. package/dist/runtime/cli-core.d.ts +2 -1
  43. package/dist/runtime/cli-core.js +2 -1
  44. package/dist/runtime/cli-doctor-environment.js +1 -3
  45. package/dist/runtime/cli-doctor-workspace-features.js +128 -10
  46. package/dist/runtime/cli-doctor-workspace-package.d.ts +25 -3
  47. package/dist/runtime/cli-doctor-workspace-package.js +35 -13
  48. package/dist/runtime/cli-doctor-workspace-shared.d.ts +2 -0
  49. package/dist/runtime/cli-doctor-workspace-shared.js +5 -0
  50. package/dist/runtime/cli-doctor-workspace.d.ts +1 -1
  51. package/dist/runtime/cli-doctor-workspace.js +16 -8
  52. package/dist/runtime/cli-doctor.js +1 -1
  53. package/dist/runtime/cli-help.js +7 -0
  54. package/dist/runtime/cli-init-templates.js +11 -1
  55. package/dist/runtime/contract-artifacts.d.ts +14 -0
  56. package/dist/runtime/contract-artifacts.js +15 -0
  57. package/dist/runtime/fs-async.d.ts +7 -0
  58. package/dist/runtime/fs-async.js +11 -2
  59. package/dist/runtime/index.d.ts +1 -1
  60. package/dist/runtime/index.js +1 -1
  61. package/dist/runtime/migration-maintenance-verify.js +3 -0
  62. package/dist/runtime/migration-render-generated.js +4 -0
  63. package/dist/runtime/package-versions.js +3 -7
  64. package/dist/runtime/rest-resource-artifacts.d.ts +57 -1
  65. package/dist/runtime/rest-resource-artifacts.js +97 -1
  66. package/dist/runtime/scaffold-repository-reference.js +3 -7
  67. package/dist/runtime/template-render.d.ts +1 -1
  68. package/dist/runtime/template-render.js +1 -1
  69. package/dist/runtime/template-source-cache-markers.d.ts +37 -0
  70. package/dist/runtime/template-source-cache-markers.js +125 -0
  71. package/dist/runtime/template-source-cache.d.ts +1 -4
  72. package/dist/runtime/template-source-cache.js +16 -122
  73. package/dist/runtime/template-source-external.d.ts +4 -2
  74. package/dist/runtime/template-source-external.js +4 -2
  75. package/dist/runtime/template-source-remote.d.ts +8 -4
  76. package/dist/runtime/template-source-remote.js +8 -4
  77. package/dist/runtime/typia-llm.js +3 -4
  78. package/dist/runtime/workspace-inventory-mutations.d.ts +24 -0
  79. package/dist/runtime/workspace-inventory-mutations.js +181 -0
  80. package/dist/runtime/workspace-inventory-parser.d.ts +53 -0
  81. package/dist/runtime/workspace-inventory-parser.js +632 -0
  82. package/dist/runtime/workspace-inventory-read.d.ts +51 -0
  83. package/dist/runtime/workspace-inventory-read.js +98 -0
  84. package/dist/runtime/workspace-inventory-templates.d.ts +50 -0
  85. package/dist/runtime/workspace-inventory-templates.js +268 -0
  86. package/dist/runtime/workspace-inventory-types.d.ts +220 -0
  87. package/dist/runtime/workspace-inventory-types.js +1 -0
  88. package/dist/runtime/workspace-inventory.d.ts +5 -252
  89. package/dist/runtime/workspace-inventory.js +4 -928
  90. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { quoteTsString, } from "./cli-add-shared.js";
2
- import { buildRestResourceEndpointManifest } from "./rest-resource-artifacts.js";
2
+ import { buildManualRestContractEndpointManifest, buildRestResourceEndpointManifest, } from "./rest-resource-artifacts.js";
3
3
  import { toPascalCase, toTitleCase } from "./string-case.js";
4
4
  function indentMultiline(source, prefix) {
5
5
  return source
@@ -7,33 +7,287 @@ function indentMultiline(source, prefix) {
7
7
  .map((line) => `${prefix}${line}`)
8
8
  .join("\n");
9
9
  }
10
- export function buildRestResourceConfigEntry(restResourceSlug, namespace, methods) {
11
- const pascalCase = toPascalCase(restResourceSlug);
12
- const title = toTitleCase(restResourceSlug);
10
+ /**
11
+ * Build a generated REST resource config entry for `scripts/block-config.ts`.
12
+ *
13
+ * @param options REST resource metadata. `restResourceSlug`, `namespace`, and
14
+ * `methods` are required; `controllerClass`, `controllerExtends`,
15
+ * `permissionCallback`, and `routePattern` opt into generated controller,
16
+ * permission, and item-route escape hatches.
17
+ * @returns TypeScript object literal source for one generated REST resource entry.
18
+ */
19
+ export function buildRestResourceConfigEntry(options) {
20
+ const pascalCase = toPascalCase(options.restResourceSlug);
21
+ const title = toTitleCase(options.restResourceSlug);
13
22
  const manifest = buildRestResourceEndpointManifest({
14
- namespace,
23
+ namespace: options.namespace,
24
+ pascalCase,
25
+ ...(options.routePattern ? { routePattern: options.routePattern } : {}),
26
+ slugKebabCase: options.restResourceSlug,
27
+ title,
28
+ }, options.methods);
29
+ return [
30
+ "\t{",
31
+ `\t\tapiFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api.ts`)},`,
32
+ ...(options.controllerClass
33
+ ? [`\t\tcontrollerClass: ${quoteTsString(options.controllerClass)},`]
34
+ : []),
35
+ ...(options.controllerExtends
36
+ ? [`\t\tcontrollerExtends: ${quoteTsString(options.controllerExtends)},`]
37
+ : []),
38
+ `\t\tclientFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api-client.ts`)},`,
39
+ `\t\tdataFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/data.ts`)},`,
40
+ `\t\tmethods: [ ${options.methods.map((method) => quoteTsString(method)).join(", ")} ],`,
41
+ `\t\tnamespace: ${quoteTsString(options.namespace)},`,
42
+ `\t\topenApiFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api.openapi.json`)},`,
43
+ ...(options.permissionCallback
44
+ ? [`\t\tpermissionCallback: ${quoteTsString(options.permissionCallback)},`]
45
+ : []),
46
+ `\t\tphpFile: ${quoteTsString(`inc/rest/${options.restResourceSlug}.php`)},`,
47
+ "\t\trestManifest: defineEndpointManifest(",
48
+ indentMultiline(JSON.stringify(manifest, null, "\t"), "\t\t\t"),
49
+ "\t\t),",
50
+ ...(options.routePattern
51
+ ? [`\t\troutePattern: ${quoteTsString(options.routePattern)},`]
52
+ : []),
53
+ `\t\tslug: ${quoteTsString(options.restResourceSlug)},`,
54
+ `\t\ttypesFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api-types.ts`)},`,
55
+ `\t\tvalidatorsFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api-validators.ts`)},`,
56
+ "\t},",
57
+ ].join("\n");
58
+ }
59
+ /**
60
+ * Build the `REST_RESOURCES` config entry appended for a manual REST contract.
61
+ *
62
+ * @param options Manual contract file, route, type, and auth metadata.
63
+ * @param options.auth Auth intent stored in the endpoint manifest.
64
+ * @param options.bodyTypeName Optional exported body type name.
65
+ * @param options.method Uppercase HTTP method for the external route.
66
+ * @param options.namespace REST namespace such as `vendor/v1`.
67
+ * @param options.pathPattern Route pattern relative to the namespace.
68
+ * @param options.queryTypeName Exported query type name.
69
+ * @param options.responseTypeName Exported response type name.
70
+ * @param options.restResourceSlug Normalized workspace REST contract slug.
71
+ * @returns A TypeScript object literal string for `scripts/block-config.ts`.
72
+ */
73
+ export function buildManualRestContractConfigEntry(options) {
74
+ const pascalCase = toPascalCase(options.restResourceSlug);
75
+ const title = toTitleCase(options.restResourceSlug);
76
+ const manifest = buildManualRestContractEndpointManifest({
77
+ auth: options.auth,
78
+ ...(options.bodyTypeName ? { bodyTypeName: options.bodyTypeName } : {}),
79
+ method: options.method,
80
+ namespace: options.namespace,
15
81
  pascalCase,
16
- slugKebabCase: restResourceSlug,
82
+ pathPattern: options.pathPattern,
83
+ queryTypeName: options.queryTypeName,
84
+ responseTypeName: options.responseTypeName,
85
+ slugKebabCase: options.restResourceSlug,
17
86
  title,
18
- }, methods);
87
+ });
19
88
  return [
20
89
  "\t{",
21
- `\t\tapiFile: ${quoteTsString(`src/rest/${restResourceSlug}/api.ts`)},`,
22
- `\t\tclientFile: ${quoteTsString(`src/rest/${restResourceSlug}/api-client.ts`)},`,
23
- `\t\tdataFile: ${quoteTsString(`src/rest/${restResourceSlug}/data.ts`)},`,
24
- `\t\tmethods: [ ${methods.map((method) => quoteTsString(method)).join(", ")} ],`,
25
- `\t\tnamespace: ${quoteTsString(namespace)},`,
26
- `\t\topenApiFile: ${quoteTsString(`src/rest/${restResourceSlug}/api.openapi.json`)},`,
27
- `\t\tphpFile: ${quoteTsString(`inc/rest/${restResourceSlug}.php`)},`,
90
+ `\t\tapiFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api.ts`)},`,
91
+ `\t\tauth: ${quoteTsString(options.auth)},`,
92
+ ...(options.bodyTypeName
93
+ ? [`\t\tbodyTypeName: ${quoteTsString(options.bodyTypeName)},`]
94
+ : []),
95
+ `\t\tclientFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api-client.ts`)},`,
96
+ `\t\tmethod: ${quoteTsString(options.method)},`,
97
+ "\t\tmethods: [],",
98
+ "\t\tmode: 'manual',",
99
+ `\t\tnamespace: ${quoteTsString(options.namespace)},`,
100
+ `\t\topenApiFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api.openapi.json`)},`,
101
+ `\t\tpathPattern: ${quoteTsString(options.pathPattern)},`,
102
+ `\t\tqueryTypeName: ${quoteTsString(options.queryTypeName)},`,
28
103
  "\t\trestManifest: defineEndpointManifest(",
29
104
  indentMultiline(JSON.stringify(manifest, null, "\t"), "\t\t\t"),
30
105
  "\t\t),",
31
- `\t\tslug: ${quoteTsString(restResourceSlug)},`,
32
- `\t\ttypesFile: ${quoteTsString(`src/rest/${restResourceSlug}/api-types.ts`)},`,
33
- `\t\tvalidatorsFile: ${quoteTsString(`src/rest/${restResourceSlug}/api-validators.ts`)},`,
106
+ `\t\tresponseTypeName: ${quoteTsString(options.responseTypeName)},`,
107
+ ...(options.secretFieldName
108
+ ? [`\t\tsecretFieldName: ${quoteTsString(options.secretFieldName)},`]
109
+ : []),
110
+ ...(options.secretStateFieldName
111
+ ? [`\t\tsecretStateFieldName: ${quoteTsString(options.secretStateFieldName)},`]
112
+ : []),
113
+ `\t\tslug: ${quoteTsString(options.restResourceSlug)},`,
114
+ `\t\ttypesFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api-types.ts`)},`,
115
+ `\t\tvalidatorsFile: ${quoteTsString(`src/rest/${options.restResourceSlug}/api-validators.ts`)},`,
34
116
  "\t},",
35
117
  ].join("\n");
36
118
  }
119
+ /**
120
+ * Build the editable TypeScript type source for a manual REST contract.
121
+ *
122
+ * @param options Manual contract type naming metadata.
123
+ * @param options.bodyTypeName Optional exported body type name.
124
+ * @param options.queryTypeName Exported query type name.
125
+ * @param options.responseTypeName Exported response type name.
126
+ * @param options.restResourceSlug Normalized workspace REST contract slug.
127
+ * @param options.secretFieldName Optional raw secret field included only in the request body.
128
+ * @param options.secretStateFieldName Optional masked response boolean field.
129
+ * @returns TypeScript source for `api-types.ts`.
130
+ */
131
+ export function buildManualRestContractTypesSource(options) {
132
+ const title = toTitleCase(options.restResourceSlug);
133
+ const lines = [
134
+ "import type { tags } from '@wp-typia/block-runtime/typia-tags';",
135
+ "",
136
+ `export interface ${options.queryTypeName} {`,
137
+ "\tid?: string & tags.MinLength< 1 >;",
138
+ "\tpreview?: boolean;",
139
+ "}",
140
+ ];
141
+ if (options.bodyTypeName) {
142
+ const secretLines = options.secretFieldName && options.secretStateFieldName
143
+ ? [
144
+ `\t${options.secretFieldName}?: string & tags.MinLength< 1 > & tags.MaxLength< 4096 > & tags.Secret< ${quoteTsString(options.secretStateFieldName)} >;`,
145
+ `\t// ${options.secretFieldName} is write-only: persist it server-side and expose ${options.secretStateFieldName} in responses instead of returning the raw value.`,
146
+ ]
147
+ : [];
148
+ lines.push("", `export interface ${options.bodyTypeName} {`, ...secretLines, "\tpayload: string & tags.MinLength< 1 >;", "\tcomment?: string & tags.MaxLength< 500 >;", "}");
149
+ }
150
+ lines.push("", `export interface ${options.responseTypeName} {`, ...(options.secretStateFieldName
151
+ ? [
152
+ `\t${options.secretStateFieldName}: boolean;`,
153
+ `\t// Raw secret fields such as ${options.secretFieldName ?? "the request secret"} must never be returned in this response.`,
154
+ ]
155
+ : []), "\tid: string & tags.MinLength< 1 >;", "\tstatus: 'ok' | 'error';", "\tmessage?: string;", "\tupdatedAt?: string;", "}", "", `// ${title} is a manual REST contract: edit these types to match the external route owner.`);
156
+ return `${lines.join("\n")}\n`;
157
+ }
158
+ /**
159
+ * Build Typia validator source for a manual REST contract.
160
+ *
161
+ * @param options Manual contract type names to validate.
162
+ * @param options.bodyTypeName Optional exported body type name.
163
+ * @param options.queryTypeName Exported query type name.
164
+ * @param options.responseTypeName Exported response type name.
165
+ * @returns TypeScript source for `api-validators.ts`.
166
+ */
167
+ export function buildManualRestContractValidatorsSource(options) {
168
+ const importedTypes = [
169
+ options.queryTypeName,
170
+ ...(options.bodyTypeName ? [options.bodyTypeName] : []),
171
+ options.responseTypeName,
172
+ ].sort();
173
+ const validatorDeclarations = [
174
+ `const validateQuery = typia.createValidate< ${options.queryTypeName} >();`,
175
+ ...(options.bodyTypeName
176
+ ? [`const validateRequest = typia.createValidate< ${options.bodyTypeName} >();`]
177
+ : []),
178
+ `const validateResponse = typia.createValidate< ${options.responseTypeName} >();`,
179
+ ];
180
+ const validatorEntries = [
181
+ `\tquery: ( input: unknown ) => toValidationResult< ${options.queryTypeName} >( validateQuery( input ) ),`,
182
+ ...(options.bodyTypeName
183
+ ? [
184
+ `\trequest: ( input: unknown ) => toValidationResult< ${options.bodyTypeName} >( validateRequest( input ) ),`,
185
+ ]
186
+ : []),
187
+ `\tresponse: ( input: unknown ) => toValidationResult< ${options.responseTypeName} >( validateResponse( input ) ),`,
188
+ ];
189
+ return `import typia from 'typia';
190
+
191
+ import { toValidationResult } from '@wp-typia/rest';
192
+ import type {
193
+ \t${importedTypes.join(",\n\t")},
194
+ } from './api-types';
195
+
196
+ ${validatorDeclarations.join("\n")}
197
+
198
+ export const apiValidators = {
199
+ ${validatorEntries.join("\n")}
200
+ };
201
+ `;
202
+ }
203
+ /**
204
+ * Build the public API shim for a manual REST contract.
205
+ *
206
+ * @param options Manual REST contract operation and request type metadata.
207
+ * @returns TypeScript source that re-exports the generated endpoint client.
208
+ */
209
+ export function buildManualRestContractApiSource(options) {
210
+ const pascalCase = toPascalCase(options.restResourceSlug);
211
+ const operationId = `call${pascalCase}ManualRestContract`;
212
+ const requestTypeName = options.bodyTypeName
213
+ ? `${pascalCase}ManualRestContractRequest`
214
+ : options.queryTypeName;
215
+ const requestTypeSource = options.bodyTypeName
216
+ ? `export interface ${requestTypeName} {
217
+ \tbody: ${options.bodyTypeName};
218
+ \tquery: ${options.queryTypeName};
219
+ }
220
+
221
+ `
222
+ : "";
223
+ const typeImports = options.bodyTypeName
224
+ ? [options.bodyTypeName, options.queryTypeName]
225
+ : [options.queryTypeName];
226
+ return `import {
227
+ \tcallEndpoint,
228
+ \tresolveRestRouteUrl,
229
+ } from '@wp-typia/rest';
230
+
231
+ import type {
232
+ \t${typeImports.sort().join(",\n\t")},
233
+ } from './api-types';
234
+ import { ${operationId}Endpoint } from './api-client';
235
+
236
+ export * from './api-client';
237
+
238
+ ${requestTypeSource}function resolveRestNonce(fallback?: string): string | undefined {
239
+ \tif (typeof fallback === 'string' && fallback.length > 0) {
240
+ \t\treturn fallback;
241
+ \t}
242
+
243
+ \tif (typeof window === 'undefined') {
244
+ \t\treturn undefined;
245
+ \t}
246
+
247
+ \tconst wpApiSettings = (
248
+ \t\twindow as typeof window & {
249
+ \t\t\twpApiSettings?: { nonce?: string };
250
+ \t\t}
251
+ \t).wpApiSettings;
252
+
253
+ \treturn typeof wpApiSettings?.nonce === 'string' &&
254
+ \t\twpApiSettings.nonce.length > 0
255
+ \t\t? wpApiSettings.nonce
256
+ \t\t: undefined;
257
+ }
258
+
259
+ function resolveEndpointRouteOptions(request: ${requestTypeName}) {
260
+ \tconst requestOptions = ${operationId}Endpoint.buildRequestOptions?.(request) ?? {};
261
+ \tconst nonce = resolveRestNonce();
262
+ \tconst requestHeaders = (
263
+ \t\trequestOptions as { headers?: Record<string, string> }
264
+ \t).headers;
265
+
266
+ \treturn {
267
+ \t\t...requestOptions,
268
+ \t\theaders: nonce
269
+ \t\t\t? {
270
+ \t\t\t\t\t...(requestHeaders ?? {}),
271
+ \t\t\t\t\t'X-WP-Nonce': nonce,
272
+ \t\t\t\t}
273
+ \t\t\t: requestHeaders,
274
+ \t\tpath: undefined,
275
+ \t\turl:
276
+ \t\t\trequestOptions.url ??
277
+ \t\t\tresolveRestRouteUrl(requestOptions.path ?? ${operationId}Endpoint.path),
278
+ \t};
279
+ }
280
+
281
+ export const manualRestContractEndpoint = {
282
+ \t...${operationId}Endpoint,
283
+ \tbuildRequestOptions: resolveEndpointRouteOptions,
284
+ };
285
+
286
+ export function callManualRestContract(request: ${requestTypeName}) {
287
+ \treturn callEndpoint(manualRestContractEndpoint, request);
288
+ }
289
+ `;
290
+ }
37
291
  export function buildRestResourceTypesSource(restResourceSlug, methods) {
38
292
  const pascalCase = toPascalCase(restResourceSlug);
39
293
  const lines = [
@@ -122,9 +376,8 @@ export function buildRestResourceApiSource(restResourceSlug, methods) {
122
376
  clientEndpointImports.push(`list${pascalCase}ResourcesEndpoint`);
123
377
  exportedBindings.push(`export const restResourceListEndpoint = {
124
378
  \t...list${pascalCase}ResourcesEndpoint,
125
- \tbuildRequestOptions: () => ( {
126
- \t\turl: resolveRestRouteUrl( list${pascalCase}ResourcesEndpoint.path ),
127
- \t} ),
379
+ \tbuildRequestOptions: ( request: ${pascalCase}ListQuery ) =>
380
+ \t\tresolveEndpointRouteOptions( list${pascalCase}ResourcesEndpoint, request ),
128
381
  };
129
382
 
130
383
  export function listResource( request: ${pascalCase}ListQuery ) {
@@ -136,9 +389,8 @@ export function listResource( request: ${pascalCase}ListQuery ) {
136
389
  clientEndpointImports.push(`read${pascalCase}ResourceEndpoint`);
137
390
  exportedBindings.push(`export const restResourceReadEndpoint = {
138
391
  \t...read${pascalCase}ResourceEndpoint,
139
- \tbuildRequestOptions: () => ( {
140
- \t\turl: resolveRestRouteUrl( read${pascalCase}ResourceEndpoint.path ),
141
- \t} ),
392
+ \tbuildRequestOptions: ( request: ${pascalCase}ReadQuery ) =>
393
+ \t\tresolveEndpointRouteOptions( read${pascalCase}ResourceEndpoint, request ),
142
394
  };
143
395
 
144
396
  export function readResource( request: ${pascalCase}ReadQuery ) {
@@ -150,15 +402,15 @@ export function readResource( request: ${pascalCase}ReadQuery ) {
150
402
  clientEndpointImports.push(`create${pascalCase}ResourceEndpoint`);
151
403
  exportedBindings.push(`export const restResourceCreateEndpoint = {
152
404
  \t...create${pascalCase}ResourceEndpoint,
153
- \tbuildRequestOptions: () => {
405
+ \tbuildRequestOptions: ( request: ${pascalCase}CreateRequest ) => {
154
406
  \t\tconst nonce = resolveRestNonce();
155
407
  \t\treturn {
408
+ \t\t\t...resolveEndpointRouteOptions( create${pascalCase}ResourceEndpoint, request ),
156
409
  \t\t\theaders: nonce
157
410
  \t\t\t\t? {
158
411
  \t\t\t\t\t'X-WP-Nonce': nonce,
159
412
  \t\t\t\t}
160
413
  \t\t\t\t: undefined,
161
- \t\t\turl: resolveRestRouteUrl( create${pascalCase}ResourceEndpoint.path ),
162
414
  \t\t};
163
415
  \t},
164
416
  };
@@ -173,15 +425,18 @@ export function createResource( request: ${pascalCase}CreateRequest ) {
173
425
  clientEndpointImports.push(`update${pascalCase}ResourceEndpoint`);
174
426
  exportedBindings.push(`export const restResourceUpdateEndpoint = {
175
427
  \t...update${pascalCase}ResourceEndpoint,
176
- \tbuildRequestOptions: () => {
428
+ \tbuildRequestOptions: ( request: {
429
+ \t\tbody: ${pascalCase}UpdateRequest;
430
+ \t\tquery: ${pascalCase}UpdateQuery;
431
+ \t} ) => {
177
432
  \t\tconst nonce = resolveRestNonce();
178
433
  \t\treturn {
434
+ \t\t\t...resolveEndpointRouteOptions( update${pascalCase}ResourceEndpoint, request ),
179
435
  \t\t\theaders: nonce
180
436
  \t\t\t\t? {
181
437
  \t\t\t\t\t'X-WP-Nonce': nonce,
182
438
  \t\t\t\t}
183
439
  \t\t\t\t: undefined,
184
- \t\t\turl: resolveRestRouteUrl( update${pascalCase}ResourceEndpoint.path ),
185
440
  \t\t};
186
441
  \t},
187
442
  };
@@ -198,15 +453,15 @@ export function updateResource( request: {
198
453
  clientEndpointImports.push(`delete${pascalCase}ResourceEndpoint`);
199
454
  exportedBindings.push(`export const restResourceDeleteEndpoint = {
200
455
  \t...delete${pascalCase}ResourceEndpoint,
201
- \tbuildRequestOptions: () => {
456
+ \tbuildRequestOptions: ( request: ${pascalCase}DeleteQuery ) => {
202
457
  \t\tconst nonce = resolveRestNonce();
203
458
  \t\treturn {
459
+ \t\t\t...resolveEndpointRouteOptions( delete${pascalCase}ResourceEndpoint, request ),
204
460
  \t\t\theaders: nonce
205
461
  \t\t\t\t? {
206
462
  \t\t\t\t\t'X-WP-Nonce': nonce,
207
463
  \t\t\t\t}
208
464
  \t\t\t\t: undefined,
209
- \t\t\turl: resolveRestRouteUrl( delete${pascalCase}ResourceEndpoint.path ),
210
465
  \t\t};
211
466
  \t},
212
467
  };
@@ -251,6 +506,24 @@ import {
251
506
  \t${clientEndpointImports.sort().join(",\n\t")},
252
507
  } from './api-client';
253
508
  ${resolveRestNonceSource}
509
+ function resolveEndpointRouteOptions<TRequest>(
510
+ \tendpoint: {
511
+ \t\tbuildRequestOptions?: ( request: TRequest ) => {
512
+ \t\t\tpath?: string;
513
+ \t\t\turl?: string;
514
+ \t\t};
515
+ \t\tpath: string;
516
+ \t},
517
+ \trequest: TRequest
518
+ ) {
519
+ \tconst requestOptions = endpoint.buildRequestOptions?.( request ) ?? {};
520
+ \treturn {
521
+ \t\t...requestOptions,
522
+ \t\tpath: undefined,
523
+ \t\turl: requestOptions.url ?? resolveRestRouteUrl( requestOptions.path ?? endpoint.path ),
524
+ \t};
525
+ }
526
+
254
527
  ${exportedBindings.join("\n\n")}
255
528
  `;
256
529
  }
@@ -1,4 +1,4 @@
1
- import { type RestResourceMethodId, type RunAddRestResourceCommandOptions } from "./cli-add-shared.js";
1
+ import { type ManualRestContractAuthId, type ManualRestContractHttpMethodId, type RestResourceMethodId, type RunAddRestResourceCommandOptions } from "./cli-add-shared.js";
2
2
  /**
3
3
  * Scaffold a workspace-level REST resource and synchronize its generated
4
4
  * TypeScript and PHP artifacts.
@@ -6,9 +6,22 @@ import { type RestResourceMethodId, type RunAddRestResourceCommandOptions } from
6
6
  * @param options Command options for the REST resource scaffold workflow.
7
7
  * @returns Resolved scaffold metadata for the created REST resource.
8
8
  */
9
- export declare function runAddRestResourceCommand({ cwd, methods, namespace, restResourceName, }: RunAddRestResourceCommandOptions): Promise<{
9
+ export declare function runAddRestResourceCommand({ auth, bodyTypeName, controllerClass, controllerExtends, cwd, manual, method, methods, namespace, permissionCallback, pathPattern, queryTypeName, restResourceName, responseTypeName, routePattern, secretFieldName, secretStateFieldName, }: RunAddRestResourceCommandOptions): Promise<{
10
+ auth?: ManualRestContractAuthId;
11
+ bodyTypeName?: string;
12
+ controllerClass?: string;
13
+ controllerExtends?: string;
14
+ method?: ManualRestContractHttpMethodId;
10
15
  methods: RestResourceMethodId[];
16
+ mode: "generated" | "manual";
11
17
  namespace: string;
18
+ permissionCallback?: string;
19
+ pathPattern?: string;
12
20
  projectDir: string;
21
+ queryTypeName?: string;
13
22
  restResourceSlug: string;
23
+ responseTypeName?: string;
24
+ routePattern?: string;
25
+ secretFieldName?: string;
26
+ secretStateFieldName?: string;
14
27
  }>;