@wp-typia/project-tools 0.16.11 → 0.16.12
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 +9 -3
- package/dist/runtime/built-in-block-artifact-documents.d.ts +3 -0
- package/dist/runtime/built-in-block-artifact-documents.js +2 -0
- package/dist/runtime/built-in-block-artifact-types.d.ts +51 -0
- package/dist/runtime/built-in-block-artifact-types.js +304 -0
- package/dist/runtime/built-in-block-artifacts.js +4 -803
- package/dist/runtime/built-in-block-attribute-emitters.d.ts +71 -0
- package/dist/runtime/built-in-block-attribute-emitters.js +176 -0
- package/dist/runtime/built-in-block-attribute-specs.d.ts +38 -0
- package/dist/runtime/built-in-block-attribute-specs.js +358 -0
- package/dist/runtime/built-in-block-code-templates/basic.d.ts +4 -0
- package/dist/runtime/built-in-block-code-templates/basic.js +249 -0
- package/dist/runtime/built-in-block-code-templates/compound-child.d.ts +4 -0
- package/dist/runtime/built-in-block-code-templates/compound-child.js +138 -0
- package/dist/runtime/built-in-block-code-templates/compound-parent.d.ts +6 -0
- package/dist/runtime/built-in-block-code-templates/compound-parent.js +227 -0
- package/dist/runtime/built-in-block-code-templates/compound-persistence.d.ts +4 -0
- package/dist/runtime/built-in-block-code-templates/compound-persistence.js +478 -0
- package/dist/runtime/built-in-block-code-templates/compound.d.ts +3 -0
- package/dist/runtime/built-in-block-code-templates/compound.js +3 -0
- package/dist/runtime/built-in-block-code-templates/interactivity.d.ts +5 -0
- package/dist/runtime/built-in-block-code-templates/interactivity.js +547 -0
- package/dist/runtime/built-in-block-code-templates/persistence.d.ts +5 -0
- package/dist/runtime/built-in-block-code-templates/persistence.js +550 -0
- package/dist/runtime/built-in-block-code-templates/shared.d.ts +16 -0
- package/dist/runtime/built-in-block-code-templates/shared.js +53 -0
- package/dist/runtime/built-in-block-code-templates.d.ts +5 -32
- package/dist/runtime/built-in-block-code-templates.js +5 -2230
- package/dist/runtime/cli-add-block-config.d.ts +6 -0
- package/dist/runtime/cli-add-block-config.js +143 -0
- package/dist/runtime/cli-add-block-legacy-validator.d.ts +4 -0
- package/dist/runtime/cli-add-block-legacy-validator.js +168 -0
- package/dist/runtime/cli-add-block.js +3 -301
- package/dist/runtime/cli-add-workspace-assets.d.ts +38 -0
- package/dist/runtime/cli-add-workspace-assets.js +399 -0
- package/dist/runtime/cli-add-workspace.d.ts +2 -38
- package/dist/runtime/cli-add-workspace.js +5 -396
- package/dist/runtime/cli-doctor-environment.d.ts +12 -0
- package/dist/runtime/cli-doctor-environment.js +123 -0
- package/dist/runtime/cli-doctor-workspace.d.ts +14 -0
- package/dist/runtime/cli-doctor-workspace.js +296 -0
- package/dist/runtime/cli-doctor.d.ts +4 -2
- package/dist/runtime/cli-doctor.js +10 -405
- package/dist/runtime/migration-command-surface.d.ts +67 -0
- package/dist/runtime/migration-command-surface.js +189 -0
- package/dist/runtime/migration-diff-rename.d.ts +13 -0
- package/dist/runtime/migration-diff-rename.js +192 -0
- package/dist/runtime/migration-diff-transform.d.ts +14 -0
- package/dist/runtime/migration-diff-transform.js +105 -0
- package/dist/runtime/migration-diff.js +12 -297
- package/dist/runtime/migration-generated-artifacts.d.ts +3 -0
- package/dist/runtime/migration-generated-artifacts.js +41 -0
- package/dist/runtime/migration-maintenance.d.ts +51 -0
- package/dist/runtime/migration-maintenance.js +380 -0
- package/dist/runtime/migration-planning.d.ts +23 -0
- package/dist/runtime/migration-planning.js +131 -0
- package/dist/runtime/migration-project-config-source.d.ts +6 -0
- package/dist/runtime/migration-project-config-source.js +424 -0
- package/dist/runtime/migration-project-layout-discovery.d.ts +61 -0
- package/dist/runtime/migration-project-layout-discovery.js +337 -0
- package/dist/runtime/migration-project-layout-paths.d.ts +135 -0
- package/dist/runtime/migration-project-layout-paths.js +288 -0
- package/dist/runtime/migration-project-layout.d.ts +3 -0
- package/dist/runtime/migration-project-layout.js +2 -0
- package/dist/runtime/migration-project-workspace.d.ts +47 -0
- package/dist/runtime/migration-project-workspace.js +212 -0
- package/dist/runtime/migration-project.d.ts +4 -94
- package/dist/runtime/migration-project.js +3 -1101
- package/dist/runtime/migration-render-diff-rule.d.ts +5 -0
- package/dist/runtime/migration-render-diff-rule.js +120 -0
- package/dist/runtime/migration-render-execution.d.ts +3 -0
- package/dist/runtime/migration-render-execution.js +428 -0
- package/dist/runtime/migration-render-generated.d.ts +27 -0
- package/dist/runtime/migration-render-generated.js +230 -0
- package/dist/runtime/migration-render-support.d.ts +3 -0
- package/dist/runtime/migration-render-support.js +16 -0
- package/dist/runtime/migration-render.d.ts +3 -33
- package/dist/runtime/migration-render.js +3 -789
- package/dist/runtime/migrations.d.ts +24 -118
- package/dist/runtime/migrations.js +12 -700
- package/dist/runtime/scaffold-bootstrap.d.ts +45 -0
- package/dist/runtime/scaffold-bootstrap.js +185 -0
- package/dist/runtime/scaffold-package-manager-files.d.ts +35 -0
- package/dist/runtime/scaffold-package-manager-files.js +79 -0
- package/dist/runtime/scaffold.d.ts +1 -12
- package/dist/runtime/scaffold.js +10 -393
- package/dist/runtime/template-source-contracts.d.ts +81 -0
- package/dist/runtime/template-source-contracts.js +1 -0
- package/dist/runtime/template-source-external.d.ts +21 -0
- package/dist/runtime/template-source-external.js +184 -0
- package/dist/runtime/template-source-locators.d.ts +4 -0
- package/dist/runtime/template-source-locators.js +72 -0
- package/dist/runtime/template-source-normalization.d.ts +7 -0
- package/dist/runtime/template-source-normalization.js +53 -0
- package/dist/runtime/template-source-remote.d.ts +23 -0
- package/dist/runtime/template-source-remote.js +336 -0
- package/dist/runtime/template-source-seeds.d.ts +12 -0
- package/dist/runtime/template-source-seeds.js +243 -0
- package/dist/runtime/template-source.d.ts +4 -86
- package/dist/runtime/template-source.js +9 -828
- package/package.json +4 -4
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
export const PERSISTENCE_EDIT_TEMPLATE = `import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import {
|
|
4
|
+
AlignmentToolbar,
|
|
5
|
+
BlockControls,
|
|
6
|
+
InspectorControls,
|
|
7
|
+
RichText,
|
|
8
|
+
useBlockProps,
|
|
9
|
+
} from '@wordpress/block-editor';
|
|
10
|
+
import {
|
|
11
|
+
Notice,
|
|
12
|
+
PanelBody,
|
|
13
|
+
TextControl,
|
|
14
|
+
} from '@wordpress/components';
|
|
15
|
+
import currentManifest from './manifest-document';
|
|
16
|
+
import {
|
|
17
|
+
InspectorFromManifest,
|
|
18
|
+
useEditorFields,
|
|
19
|
+
useTypedAttributeUpdater,
|
|
20
|
+
} from '@wp-typia/block-runtime/inspector';
|
|
21
|
+
import type { {{pascalCase}}Attributes } from './types';
|
|
22
|
+
import {
|
|
23
|
+
sanitize{{pascalCase}}Attributes,
|
|
24
|
+
validate{{pascalCase}}Attributes,
|
|
25
|
+
} from './validators';
|
|
26
|
+
import { useTypiaValidation } from './hooks';
|
|
27
|
+
|
|
28
|
+
type EditProps = BlockEditProps< {{pascalCase}}Attributes >;
|
|
29
|
+
|
|
30
|
+
export default function Edit( {
|
|
31
|
+
attributes,
|
|
32
|
+
setAttributes,
|
|
33
|
+
}: EditProps ) {
|
|
34
|
+
const editorFields = useEditorFields(
|
|
35
|
+
currentManifest,
|
|
36
|
+
{
|
|
37
|
+
manual: [ 'content', 'resourceKey' ],
|
|
38
|
+
labels: {
|
|
39
|
+
buttonLabel: __( 'Button Label', '{{textDomain}}' ),
|
|
40
|
+
resourceKey: __( 'Resource Key', '{{textDomain}}' ),
|
|
41
|
+
showCount: __( 'Show Count', '{{textDomain}}' ),
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
const { errorMessages, isValid } = useTypiaValidation(
|
|
46
|
+
attributes,
|
|
47
|
+
validate{{pascalCase}}Attributes
|
|
48
|
+
);
|
|
49
|
+
const validateEditorUpdate = (
|
|
50
|
+
nextAttributes: {{pascalCase}}Attributes
|
|
51
|
+
) => {
|
|
52
|
+
try {
|
|
53
|
+
return {
|
|
54
|
+
data: sanitize{{pascalCase}}Attributes( nextAttributes ),
|
|
55
|
+
errors: [],
|
|
56
|
+
isValid: true as const,
|
|
57
|
+
};
|
|
58
|
+
} catch {
|
|
59
|
+
return validate{{pascalCase}}Attributes( nextAttributes );
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const { updateField } = useTypedAttributeUpdater(
|
|
63
|
+
attributes,
|
|
64
|
+
setAttributes,
|
|
65
|
+
validateEditorUpdate
|
|
66
|
+
);
|
|
67
|
+
const alignmentValue = editorFields.getStringValue(
|
|
68
|
+
attributes,
|
|
69
|
+
'alignment',
|
|
70
|
+
'left'
|
|
71
|
+
);
|
|
72
|
+
const persistencePolicy = '{{persistencePolicy}}';
|
|
73
|
+
const persistencePolicyDescription = __(
|
|
74
|
+
{{persistencePolicyDescriptionJson}},
|
|
75
|
+
'{{textDomain}}'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<>
|
|
80
|
+
<BlockControls>
|
|
81
|
+
<AlignmentToolbar
|
|
82
|
+
value={ alignmentValue }
|
|
83
|
+
onChange={ ( value ) =>
|
|
84
|
+
updateField(
|
|
85
|
+
'alignment',
|
|
86
|
+
( value || alignmentValue ) as NonNullable< {{pascalCase}}Attributes[ 'alignment' ] >
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
/>
|
|
90
|
+
</BlockControls>
|
|
91
|
+
<InspectorControls>
|
|
92
|
+
<InspectorFromManifest
|
|
93
|
+
attributes={ attributes }
|
|
94
|
+
fieldLookup={ editorFields }
|
|
95
|
+
onChange={ updateField }
|
|
96
|
+
paths={ [ 'alignment', 'isVisible', 'showCount', 'buttonLabel' ] }
|
|
97
|
+
title={ __( 'Persistence Settings', '{{textDomain}}' ) }
|
|
98
|
+
>
|
|
99
|
+
<TextControl
|
|
100
|
+
label={ __( 'Resource Key', '{{textDomain}}' ) }
|
|
101
|
+
value={ attributes.resourceKey ?? '' }
|
|
102
|
+
onChange={ ( value ) => updateField( 'resourceKey', value ) }
|
|
103
|
+
help={ __( 'Stable persisted identifier used by the storage-backed counter endpoint.', '{{textDomain}}' ) }
|
|
104
|
+
/>
|
|
105
|
+
<Notice status="info" isDismissible={ false }>
|
|
106
|
+
{ __( 'Storage mode: {{dataStorageMode}}', '{{textDomain}}' ) }
|
|
107
|
+
</Notice>
|
|
108
|
+
<Notice status="info" isDismissible={ false }>
|
|
109
|
+
{ __( 'Persistence policy: {{persistencePolicy}}', '{{textDomain}}' ) }
|
|
110
|
+
<br />
|
|
111
|
+
{ persistencePolicyDescription }
|
|
112
|
+
</Notice>
|
|
113
|
+
<Notice status="info" isDismissible={ false }>
|
|
114
|
+
{ __( 'Render mode: dynamic. \`render.php\` bootstraps durable post context, while fresh session-only write data is loaded from the dedicated \`/bootstrap\` endpoint after hydration.', '{{textDomain}}' ) }
|
|
115
|
+
</Notice>
|
|
116
|
+
</InspectorFromManifest>
|
|
117
|
+
{ ! isValid && (
|
|
118
|
+
<PanelBody
|
|
119
|
+
title={ __( 'Validation Errors', '{{textDomain}}' ) }
|
|
120
|
+
initialOpen
|
|
121
|
+
>
|
|
122
|
+
{ errorMessages.map( ( error, index ) => (
|
|
123
|
+
<Notice key={ index } status="error" isDismissible={ false }>
|
|
124
|
+
{ error }
|
|
125
|
+
</Notice>
|
|
126
|
+
) ) }
|
|
127
|
+
</PanelBody>
|
|
128
|
+
) }
|
|
129
|
+
</InspectorControls>
|
|
130
|
+
<div
|
|
131
|
+
{ ...useBlockProps( {
|
|
132
|
+
className: '{{cssClassName}}',
|
|
133
|
+
style: {
|
|
134
|
+
textAlign:
|
|
135
|
+
alignmentValue as NonNullable< {{pascalCase}}Attributes[ 'alignment' ] >,
|
|
136
|
+
},
|
|
137
|
+
} ) }
|
|
138
|
+
>
|
|
139
|
+
<RichText
|
|
140
|
+
tagName="p"
|
|
141
|
+
value={ attributes.content }
|
|
142
|
+
onChange={ ( value ) => updateField( 'content', value ) }
|
|
143
|
+
placeholder={ __( {{titleJson}} + ' persistence block', '{{textDomain}}' ) }
|
|
144
|
+
/>
|
|
145
|
+
<p className="{{cssClassName}}__meta">
|
|
146
|
+
{ __( 'Resource key:', '{{textDomain}}' ) } { attributes.resourceKey || '—' }
|
|
147
|
+
</p>
|
|
148
|
+
<p className="{{cssClassName}}__meta">
|
|
149
|
+
{ __( 'Storage mode:', '{{textDomain}}' ) } {{dataStorageMode}}
|
|
150
|
+
</p>
|
|
151
|
+
<p className="{{cssClassName}}__meta">
|
|
152
|
+
{ __( 'Persistence policy:', '{{textDomain}}' ) } {{persistencePolicy}}
|
|
153
|
+
</p>
|
|
154
|
+
{ ! isValid && (
|
|
155
|
+
<Notice status="error" isDismissible={ false }>
|
|
156
|
+
<ul>
|
|
157
|
+
{ errorMessages.map( ( error, index ) => <li key={ index }>{ error }</li> ) }
|
|
158
|
+
</ul>
|
|
159
|
+
</Notice>
|
|
160
|
+
) }
|
|
161
|
+
</div>
|
|
162
|
+
</>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
export const PERSISTENCE_INDEX_TEMPLATE = `import {
|
|
167
|
+
\tregisterScaffoldBlockType,
|
|
168
|
+
\ttype BlockConfiguration,
|
|
169
|
+
} from '@wp-typia/block-types/blocks/registration';
|
|
170
|
+
import {
|
|
171
|
+
\tbuildScaffoldBlockRegistration,
|
|
172
|
+
\tparseScaffoldBlockMetadata,
|
|
173
|
+
} from '@wp-typia/block-runtime/blocks';
|
|
174
|
+
|
|
175
|
+
import Edit from './edit';
|
|
176
|
+
import Save from './save';
|
|
177
|
+
import metadata from './block-metadata';
|
|
178
|
+
import './style.scss';
|
|
179
|
+
|
|
180
|
+
import type { {{pascalCase}}Attributes } from './types';
|
|
181
|
+
|
|
182
|
+
const registration = buildScaffoldBlockRegistration(
|
|
183
|
+
\tparseScaffoldBlockMetadata<BlockConfiguration< {{pascalCase}}Attributes >>( metadata ),
|
|
184
|
+
\t{
|
|
185
|
+
\t\tedit: Edit,
|
|
186
|
+
\t\tsave: Save,
|
|
187
|
+
\t}
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
registerScaffoldBlockType(registration.name, registration.settings);
|
|
191
|
+
`;
|
|
192
|
+
export const PERSISTENCE_SAVE_TEMPLATE = `export default function Save() {
|
|
193
|
+
\t// This block is intentionally server-rendered. PHP bootstraps post context,
|
|
194
|
+
\t// storage-backed state, and write-policy data before the frontend hydrates.
|
|
195
|
+
\treturn null;
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
export const PERSISTENCE_VALIDATORS_TEMPLATE = `import typia from 'typia';
|
|
199
|
+
import currentManifest from './manifest-defaults-document';
|
|
200
|
+
import type {
|
|
201
|
+
\t{{pascalCase}}Attributes,
|
|
202
|
+
\t{{pascalCase}}ValidationResult,
|
|
203
|
+
} from './types';
|
|
204
|
+
import { generateResourceKey } from '@wp-typia/block-runtime/identifiers';
|
|
205
|
+
import { createTemplateValidatorToolkit } from './validator-toolkit';
|
|
206
|
+
|
|
207
|
+
const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {
|
|
208
|
+
\tassert: typia.createAssert< {{pascalCase}}Attributes >(),
|
|
209
|
+
\tclone: typia.misc.createClone< {{pascalCase}}Attributes >() as (
|
|
210
|
+
\t\tvalue: {{pascalCase}}Attributes,
|
|
211
|
+
\t) => {{pascalCase}}Attributes,
|
|
212
|
+
\tis: typia.createIs< {{pascalCase}}Attributes >(),
|
|
213
|
+
\tmanifest: currentManifest,
|
|
214
|
+
\tprune: typia.misc.createPrune< {{pascalCase}}Attributes >(),
|
|
215
|
+
\trandom: typia.createRandom< {{pascalCase}}Attributes >() as (
|
|
216
|
+
\t\t...args: unknown[]
|
|
217
|
+
\t) => {{pascalCase}}Attributes,
|
|
218
|
+
\tfinalize: ( normalized ) => ( {
|
|
219
|
+
\t\t...normalized,
|
|
220
|
+
\t\tresourceKey:
|
|
221
|
+
\t\t\tnormalized.resourceKey && normalized.resourceKey.length > 0
|
|
222
|
+
\t\t\t\t? normalized.resourceKey
|
|
223
|
+
\t\t\t\t: generateResourceKey( '{{slugKebabCase}}' ),
|
|
224
|
+
\t} ),
|
|
225
|
+
\tvalidate: typia.createValidate< {{pascalCase}}Attributes >(),
|
|
226
|
+
} );
|
|
227
|
+
|
|
228
|
+
export const validators = scaffoldValidators.validators;
|
|
229
|
+
|
|
230
|
+
export const validate{{pascalCase}}Attributes =
|
|
231
|
+
\tscaffoldValidators.validateAttributes as (
|
|
232
|
+
\t\tattributes: unknown
|
|
233
|
+
\t) => {{pascalCase}}ValidationResult;
|
|
234
|
+
|
|
235
|
+
export const sanitize{{pascalCase}}Attributes =
|
|
236
|
+
\tscaffoldValidators.sanitizeAttributes as (
|
|
237
|
+
\t\tattributes: Partial< {{pascalCase}}Attributes >
|
|
238
|
+
\t) => {{pascalCase}}Attributes;
|
|
239
|
+
|
|
240
|
+
export const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;
|
|
241
|
+
`;
|
|
242
|
+
export const PERSISTENCE_INTERACTIVITY_TEMPLATE = `import { getContext, store } from '@wordpress/interactivity';
|
|
243
|
+
import { generatePublicWriteRequestId } from '@wp-typia/block-runtime/identifiers';
|
|
244
|
+
|
|
245
|
+
import { fetchBootstrap, fetchState, writeState } from './api';
|
|
246
|
+
import type {
|
|
247
|
+
\t{{pascalCase}}ClientState,
|
|
248
|
+
\t{{pascalCase}}Context,
|
|
249
|
+
\t{{pascalCase}}State,
|
|
250
|
+
} from './types';
|
|
251
|
+
import type {
|
|
252
|
+
\t{{pascalCase}}WriteStateRequest,
|
|
253
|
+
} from './api-types';
|
|
254
|
+
|
|
255
|
+
function hasExpiredPublicWriteToken(
|
|
256
|
+
\texpiresAt?: number
|
|
257
|
+
): boolean {
|
|
258
|
+
\treturn (
|
|
259
|
+
\t\ttypeof expiresAt === 'number' &&
|
|
260
|
+
\t\texpiresAt > 0 &&
|
|
261
|
+
\t\tDate.now() >= expiresAt * 1000
|
|
262
|
+
\t);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getWriteBlockedMessage(
|
|
266
|
+
\tcontext: {{pascalCase}}Context
|
|
267
|
+
): string {
|
|
268
|
+
\treturn context.persistencePolicy === 'authenticated'
|
|
269
|
+
\t\t? 'Sign in to persist this counter.'
|
|
270
|
+
\t\t: 'Public writes are temporarily unavailable.';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const BOOTSTRAP_MAX_ATTEMPTS = 3;
|
|
274
|
+
const BOOTSTRAP_RETRY_DELAYS_MS = [ 250, 500 ];
|
|
275
|
+
|
|
276
|
+
async function waitForBootstrapRetry( delayMs: number ): Promise< void > {
|
|
277
|
+
\tawait new Promise( ( resolve ) => {
|
|
278
|
+
\t\tsetTimeout( resolve, delayMs );
|
|
279
|
+
\t} );
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function getClientState(
|
|
283
|
+
\tcontext: {{pascalCase}}Context
|
|
284
|
+
): {{pascalCase}}ClientState {
|
|
285
|
+
\tif ( context.client ) {
|
|
286
|
+
\t\treturn context.client;
|
|
287
|
+
\t}
|
|
288
|
+
|
|
289
|
+
\tcontext.client = {
|
|
290
|
+
\t\tbootstrapError: '',
|
|
291
|
+
\t\twriteExpiry: 0,
|
|
292
|
+
\t\twriteNonce: '',
|
|
293
|
+
\t\twriteToken: '',
|
|
294
|
+
\t};
|
|
295
|
+
|
|
296
|
+
\treturn context.client;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function clearBootstrapError(
|
|
300
|
+
\tcontext: {{pascalCase}}Context,
|
|
301
|
+
\tclientState: {{pascalCase}}ClientState
|
|
302
|
+
): void {
|
|
303
|
+
\tif ( context.error === clientState.bootstrapError ) {
|
|
304
|
+
\t\tcontext.error = '';
|
|
305
|
+
\t}
|
|
306
|
+
\tclientState.bootstrapError = '';
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function setBootstrapError(
|
|
310
|
+
\tcontext: {{pascalCase}}Context,
|
|
311
|
+
\tclientState: {{pascalCase}}ClientState,
|
|
312
|
+
\tmessage: string
|
|
313
|
+
): void {
|
|
314
|
+
\tclientState.bootstrapError = message;
|
|
315
|
+
\tcontext.error = message;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const { actions, state } = store( '{{slugKebabCase}}', {
|
|
319
|
+
\tstate: {
|
|
320
|
+
\t\tisHydrated: false,
|
|
321
|
+
\t} as {{pascalCase}}State,
|
|
322
|
+
|
|
323
|
+
\tactions: {
|
|
324
|
+
\t\tasync loadState() {
|
|
325
|
+
\t\t\tconst context = getContext< {{pascalCase}}Context >();
|
|
326
|
+
\t\t\tif ( context.postId <= 0 || ! context.resourceKey ) {
|
|
327
|
+
\t\t\t\treturn;
|
|
328
|
+
\t\t\t}
|
|
329
|
+
|
|
330
|
+
\t\t\tcontext.isLoading = true;
|
|
331
|
+
\t\t\tcontext.error = '';
|
|
332
|
+
|
|
333
|
+
\t\t\ttry {
|
|
334
|
+
\t\t\t\tconst result = await fetchState( {
|
|
335
|
+
\t\t\t\t\tpostId: context.postId,
|
|
336
|
+
\t\t\t\t\tresourceKey: context.resourceKey,
|
|
337
|
+
\t\t\t\t}, {
|
|
338
|
+
\t\t\t\t\ttransportTarget: 'frontend',
|
|
339
|
+
\t\t\t\t} );
|
|
340
|
+
\t\t\t\tif ( ! result.isValid || ! result.data ) {
|
|
341
|
+
\t\t\t\t\tcontext.error = result.errors[ 0 ]?.expected ?? 'Unable to load counter';
|
|
342
|
+
\t\t\t\t\treturn;
|
|
343
|
+
\t\t\t\t}
|
|
344
|
+
\t\t\t\tcontext.count = result.data.count;
|
|
345
|
+
\t\t\t} catch ( error ) {
|
|
346
|
+
\t\t\t\tcontext.error =
|
|
347
|
+
\t\t\t\t\terror instanceof Error ? error.message : 'Unknown loading error';
|
|
348
|
+
\t\t\t} finally {
|
|
349
|
+
\t\t\t\tcontext.isLoading = false;
|
|
350
|
+
\t\t\t}
|
|
351
|
+
\t\t},
|
|
352
|
+
\t\tasync loadBootstrap() {
|
|
353
|
+
\t\t\tconst context = getContext< {{pascalCase}}Context >();
|
|
354
|
+
\t\t\tconst clientState = getClientState( context );
|
|
355
|
+
\t\t\tif ( context.postId <= 0 || ! context.resourceKey ) {
|
|
356
|
+
\t\t\t\tcontext.bootstrapReady = true;
|
|
357
|
+
\t\t\t\tcontext.canWrite = false;
|
|
358
|
+
\t\t\t\tclientState.bootstrapError = '';
|
|
359
|
+
\t\t\t\tclientState.writeExpiry = 0;
|
|
360
|
+
\t\t\t\tclientState.writeNonce = '';
|
|
361
|
+
\t\t\t\tclientState.writeToken = '';
|
|
362
|
+
\t\t\t\treturn;
|
|
363
|
+
\t\t\t}
|
|
364
|
+
|
|
365
|
+
\t\t\tcontext.isBootstrapping = true;
|
|
366
|
+
|
|
367
|
+
\t\t\tlet bootstrapSucceeded = false;
|
|
368
|
+
\t\t\tlet lastBootstrapError =
|
|
369
|
+
\t\t\t\t'Unable to initialize write access';
|
|
370
|
+
\t\t\tconst includePublicWriteCredentials = {{isPublicPersistencePolicy}};
|
|
371
|
+
\t\t\tconst includeRestNonce = {{isAuthenticatedPersistencePolicy}};
|
|
372
|
+
|
|
373
|
+
\t\t\tfor ( let attempt = 1; attempt <= BOOTSTRAP_MAX_ATTEMPTS; attempt += 1 ) {
|
|
374
|
+
\t\t\t\ttry {
|
|
375
|
+
\t\t\t\t\tconst result = await fetchBootstrap( {
|
|
376
|
+
\t\t\t\t\t\tpostId: context.postId,
|
|
377
|
+
\t\t\t\t\t\tresourceKey: context.resourceKey,
|
|
378
|
+
\t\t\t\t\t}, {
|
|
379
|
+
\t\t\t\t\t\ttransportTarget: 'frontend',
|
|
380
|
+
\t\t\t\t\t} );
|
|
381
|
+
\t\t\t\t\tif ( ! result.isValid || ! result.data ) {
|
|
382
|
+
\t\t\t\t\t\tlastBootstrapError =
|
|
383
|
+
\t\t\t\t\t\t\tresult.errors[ 0 ]?.expected ??
|
|
384
|
+
\t\t\t\t\t\t\t'Unable to initialize write access';
|
|
385
|
+
\t\t\t\t\t\tif ( attempt < BOOTSTRAP_MAX_ATTEMPTS ) {
|
|
386
|
+
\t\t\t\t\t\t\tawait waitForBootstrapRetry(
|
|
387
|
+
\t\t\t\t\t\t\t\tBOOTSTRAP_RETRY_DELAYS_MS[ attempt - 1 ] ?? 750
|
|
388
|
+
\t\t\t\t\t\t\t);
|
|
389
|
+
\t\t\t\t\t\t\tcontinue;
|
|
390
|
+
\t\t\t\t\t\t}
|
|
391
|
+
\t\t\t\t\t\tbreak;
|
|
392
|
+
\t\t\t\t\t}
|
|
393
|
+
|
|
394
|
+
\t\t\t\t\tclientState.writeExpiry =
|
|
395
|
+
\t\t\t\t\t\tincludePublicWriteCredentials &&
|
|
396
|
+
\t\t\t\t\t\t'publicWriteExpiresAt' in result.data &&
|
|
397
|
+
\t\t\t\t\t\ttypeof result.data.publicWriteExpiresAt === 'number' &&
|
|
398
|
+
\t\t\t\t\t\tresult.data.publicWriteExpiresAt > 0
|
|
399
|
+
\t\t\t\t\t\t\t? result.data.publicWriteExpiresAt
|
|
400
|
+
\t\t\t\t\t\t\t: 0;
|
|
401
|
+
\t\t\t\t\tclientState.writeToken =
|
|
402
|
+
\t\t\t\t\t\tincludePublicWriteCredentials &&
|
|
403
|
+
\t\t\t\t\t\t'publicWriteToken' in result.data &&
|
|
404
|
+
\t\t\t\t\t\ttypeof result.data.publicWriteToken === 'string' &&
|
|
405
|
+
\t\t\t\t\t\tresult.data.publicWriteToken.length > 0
|
|
406
|
+
\t\t\t\t\t\t\t? result.data.publicWriteToken
|
|
407
|
+
\t\t\t\t\t\t\t: '';
|
|
408
|
+
\t\t\t\t\tclientState.writeNonce =
|
|
409
|
+
\t\t\t\t\t\tincludeRestNonce &&
|
|
410
|
+
\t\t\t\t\t\t'restNonce' in result.data &&
|
|
411
|
+
\t\t\t\t\t\ttypeof result.data.restNonce === 'string' &&
|
|
412
|
+
\t\t\t\t\t\tresult.data.restNonce.length > 0
|
|
413
|
+
\t\t\t\t\t\t\t? result.data.restNonce
|
|
414
|
+
\t\t\t\t\t\t\t: '';
|
|
415
|
+
\t\t\t\t\tcontext.bootstrapReady = true;
|
|
416
|
+
\t\t\t\t\tcontext.canWrite =
|
|
417
|
+
\t\t\t\t\t\tresult.data.canWrite === true &&
|
|
418
|
+
\t\t\t\t\t\t(
|
|
419
|
+
\t\t\t\t\t\t\tcontext.persistencePolicy === 'authenticated'
|
|
420
|
+
\t\t\t\t\t\t\t\t? clientState.writeNonce.length > 0
|
|
421
|
+
\t\t\t\t\t\t\t\t: clientState.writeToken.length > 0 &&
|
|
422
|
+
\t\t\t\t\t\t\t\t\t! hasExpiredPublicWriteToken( clientState.writeExpiry )
|
|
423
|
+
\t\t\t\t\t\t);
|
|
424
|
+
\t\t\t\t\tclearBootstrapError( context, clientState );
|
|
425
|
+
\t\t\t\t\tbootstrapSucceeded = true;
|
|
426
|
+
\t\t\t\t\tbreak;
|
|
427
|
+
\t\t\t\t} catch ( error ) {
|
|
428
|
+
\t\t\t\t\tlastBootstrapError =
|
|
429
|
+
\t\t\t\t\t\terror instanceof Error ? error.message : 'Unknown bootstrap error';
|
|
430
|
+
\t\t\t\t\tif ( attempt < BOOTSTRAP_MAX_ATTEMPTS ) {
|
|
431
|
+
\t\t\t\t\t\tawait waitForBootstrapRetry(
|
|
432
|
+
\t\t\t\t\t\t\tBOOTSTRAP_RETRY_DELAYS_MS[ attempt - 1 ] ?? 750
|
|
433
|
+
\t\t\t\t\t\t);
|
|
434
|
+
\t\t\t\t\t\tcontinue;
|
|
435
|
+
\t\t\t\t\t}
|
|
436
|
+
\t\t\t\t\tbreak;
|
|
437
|
+
\t\t\t\t}
|
|
438
|
+
\t\t\t}
|
|
439
|
+
|
|
440
|
+
\t\t\tif ( ! bootstrapSucceeded ) {
|
|
441
|
+
\t\t\t\tcontext.bootstrapReady = false;
|
|
442
|
+
\t\t\t\tcontext.canWrite = false;
|
|
443
|
+
\t\t\t\tclientState.writeExpiry = 0;
|
|
444
|
+
\t\t\t\tclientState.writeNonce = '';
|
|
445
|
+
\t\t\t\tclientState.writeToken = '';
|
|
446
|
+
\t\t\t\tsetBootstrapError( context, clientState, lastBootstrapError );
|
|
447
|
+
\t\t\t}
|
|
448
|
+
\t\t\tcontext.isBootstrapping = false;
|
|
449
|
+
\t\t},
|
|
450
|
+
\t\tasync increment() {
|
|
451
|
+
\t\t\tconst context = getContext< {{pascalCase}}Context >();
|
|
452
|
+
\t\t\tconst clientState = getClientState( context );
|
|
453
|
+
\t\t\tif ( context.postId <= 0 || ! context.resourceKey ) {
|
|
454
|
+
\t\t\t\treturn;
|
|
455
|
+
\t\t\t}
|
|
456
|
+
\t\t\tif ( ! context.bootstrapReady ) {
|
|
457
|
+
\t\t\t\tawait actions.loadBootstrap();
|
|
458
|
+
\t\t\t}
|
|
459
|
+
\t\t\tif ( ! context.bootstrapReady ) {
|
|
460
|
+
\t\t\t\tcontext.error = 'Write access is still initializing.';
|
|
461
|
+
\t\t\t\treturn;
|
|
462
|
+
\t\t\t}
|
|
463
|
+
\t\t\tif (
|
|
464
|
+
\t\t\t\tcontext.persistencePolicy === 'public' &&
|
|
465
|
+
\t\t\t\thasExpiredPublicWriteToken( clientState.writeExpiry )
|
|
466
|
+
\t\t\t) {
|
|
467
|
+
\t\t\t\tawait actions.loadBootstrap();
|
|
468
|
+
\t\t\t}
|
|
469
|
+
\t\t\tif (
|
|
470
|
+
\t\t\t\tcontext.persistencePolicy === 'public' &&
|
|
471
|
+
\t\t\t\thasExpiredPublicWriteToken( clientState.writeExpiry )
|
|
472
|
+
\t\t\t) {
|
|
473
|
+
\t\t\t\tcontext.canWrite = false;
|
|
474
|
+
\t\t\t\tcontext.error = getWriteBlockedMessage( context );
|
|
475
|
+
\t\t\t\treturn;
|
|
476
|
+
\t\t\t}
|
|
477
|
+
\t\t\tif ( ! context.canWrite ) {
|
|
478
|
+
\t\t\t\tcontext.error = getWriteBlockedMessage( context );
|
|
479
|
+
\t\t\t\treturn;
|
|
480
|
+
\t\t\t}
|
|
481
|
+
|
|
482
|
+
\t\t\tcontext.isSaving = true;
|
|
483
|
+
\t\t\tcontext.error = '';
|
|
484
|
+
|
|
485
|
+
\t\t\ttry {
|
|
486
|
+
\t\t\t\tconst request = {
|
|
487
|
+
\t\t\t\t\tdelta: 1,
|
|
488
|
+
\t\t\t\t\tpostId: context.postId,
|
|
489
|
+
\t\t\t\t\tresourceKey: context.resourceKey,
|
|
490
|
+
\t\t\t\t} as {{pascalCase}}WriteStateRequest;
|
|
491
|
+
\t\t\t\tif ( {{isPublicPersistencePolicy}} ) {
|
|
492
|
+
\t\t\t\t\trequest.publicWriteRequestId =
|
|
493
|
+
\t\t\t\t\t\tgeneratePublicWriteRequestId() as {{pascalCase}}WriteStateRequest[ 'publicWriteRequestId' ];
|
|
494
|
+
\t\t\t\t\tif ( clientState.writeToken.length > 0 ) {
|
|
495
|
+
\t\t\t\t\t\trequest.publicWriteToken =
|
|
496
|
+
\t\t\t\t\t\t\tclientState.writeToken as {{pascalCase}}WriteStateRequest[ 'publicWriteToken' ];
|
|
497
|
+
\t\t\t\t\t}
|
|
498
|
+
\t\t\t\t}
|
|
499
|
+
\t\t\t\tconst result = await writeState( request, {
|
|
500
|
+
\t\t\t\t\trestNonce:
|
|
501
|
+
\t\t\t\t\t\tclientState.writeNonce.length > 0
|
|
502
|
+
\t\t\t\t\t\t\t? clientState.writeNonce
|
|
503
|
+
\t\t\t\t\t\t\t: undefined,
|
|
504
|
+
\t\t\t\t\ttransportTarget: 'frontend',
|
|
505
|
+
\t\t\t\t} );
|
|
506
|
+
\t\t\t\tif ( ! result.isValid || ! result.data ) {
|
|
507
|
+
\t\t\t\t\tcontext.error = result.errors[ 0 ]?.expected ?? 'Unable to update counter';
|
|
508
|
+
\t\t\t\t\treturn;
|
|
509
|
+
\t\t\t\t}
|
|
510
|
+
\t\t\t\tcontext.count = result.data.count;
|
|
511
|
+
\t\t\t\tcontext.storage = result.data.storage;
|
|
512
|
+
\t\t\t} catch ( error ) {
|
|
513
|
+
\t\t\t\tcontext.error =
|
|
514
|
+
\t\t\t\t\terror instanceof Error ? error.message : 'Unknown update error';
|
|
515
|
+
\t\t\t} finally {
|
|
516
|
+
\t\t\t\tcontext.isSaving = false;
|
|
517
|
+
\t\t\t}
|
|
518
|
+
\t\t},
|
|
519
|
+
\t},
|
|
520
|
+
|
|
521
|
+
\tcallbacks: {
|
|
522
|
+
\t\tinit() {
|
|
523
|
+
\t\t\tconst context = getContext< {{pascalCase}}Context >();
|
|
524
|
+
\t\t\tcontext.client = {
|
|
525
|
+
\t\t\t\tbootstrapError: '',
|
|
526
|
+
\t\t\t\twriteExpiry: 0,
|
|
527
|
+
\t\t\t\twriteNonce: '',
|
|
528
|
+
\t\t\t\twriteToken: '',
|
|
529
|
+
\t\t\t};
|
|
530
|
+
\t\t\tcontext.bootstrapReady = false;
|
|
531
|
+
\t\t\tcontext.canWrite = false;
|
|
532
|
+
\t\t\tcontext.count = 0;
|
|
533
|
+
\t\t\tcontext.error = '';
|
|
534
|
+
\t\t\tcontext.isBootstrapping = false;
|
|
535
|
+
\t\t\tcontext.isLoading = false;
|
|
536
|
+
\t\t\tcontext.isSaving = false;
|
|
537
|
+
\t\t},
|
|
538
|
+
\t\tmounted() {
|
|
539
|
+
\t\t\tstate.isHydrated = true;
|
|
540
|
+
\t\t\tif ( typeof document !== 'undefined' ) {
|
|
541
|
+
\t\t\t\tdocument.documentElement.dataset[ '{{slugCamelCase}}Hydrated' ] = 'true';
|
|
542
|
+
\t\t\t}
|
|
543
|
+
\t\t\tvoid Promise.allSettled( [
|
|
544
|
+
\t\t\t\tactions.loadState(),
|
|
545
|
+
\t\t\t\tactions.loadBootstrap(),
|
|
546
|
+
\t\t\t] );
|
|
547
|
+
\t\t},
|
|
548
|
+
\t},
|
|
549
|
+
} );
|
|
550
|
+
`;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for the shared validation hooks module used by built-in scaffolds.
|
|
3
|
+
*/
|
|
4
|
+
export declare const SHARED_HOOKS_TEMPLATE = "import { useMemo } from '@wordpress/element';\n\nimport {\n\tcreateUseTypiaValidationHook,\n\tformatValidationError,\n\tformatValidationErrors,\n} from '@wp-typia/block-runtime/validation';\n\nexport {\n\tformatValidationError,\n\tformatValidationErrors,\n\ttype TypiaValidationError,\n\ttype ValidationResult,\n\ttype ValidationState,\n} from '@wp-typia/block-runtime/validation';\n\nexport const useTypiaValidation = createUseTypiaValidationHook( {\n\tuseMemo,\n} );\n";
|
|
5
|
+
/**
|
|
6
|
+
* Template for the generated block metadata wrapper around `block.json`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const BLOCK_METADATA_WRAPPER_TEMPLATE = "import rawMetadata from './block.json';\nimport { defineScaffoldBlockMetadata } from '@wp-typia/block-runtime/blocks';\n\nconst metadata = defineScaffoldBlockMetadata(rawMetadata);\n\nexport default metadata;\n";
|
|
9
|
+
/**
|
|
10
|
+
* Template for the generated manifest document wrapper around `typia.manifest.json`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MANIFEST_DOCUMENT_WRAPPER_TEMPLATE = "import rawCurrentManifest from './typia.manifest.json';\nimport { defineManifestDocument } from '@wp-typia/block-runtime/editor';\n\nconst currentManifest = defineManifestDocument(rawCurrentManifest);\n\nexport default currentManifest;\n";
|
|
13
|
+
/**
|
|
14
|
+
* Template for the generated manifest-defaults wrapper used by validators.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MANIFEST_DEFAULTS_DOCUMENT_WRAPPER_TEMPLATE = "import rawCurrentManifest from './typia.manifest.json';\nimport { defineManifestDefaultsDocument } from '@wp-typia/block-runtime/defaults';\n\nconst currentManifest = defineManifestDefaultsDocument(rawCurrentManifest);\n\nexport default currentManifest;\n";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for the shared validation hooks module used by built-in scaffolds.
|
|
3
|
+
*/
|
|
4
|
+
export const SHARED_HOOKS_TEMPLATE = `import { useMemo } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
createUseTypiaValidationHook,
|
|
8
|
+
formatValidationError,
|
|
9
|
+
formatValidationErrors,
|
|
10
|
+
} from '@wp-typia/block-runtime/validation';
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
formatValidationError,
|
|
14
|
+
formatValidationErrors,
|
|
15
|
+
type TypiaValidationError,
|
|
16
|
+
type ValidationResult,
|
|
17
|
+
type ValidationState,
|
|
18
|
+
} from '@wp-typia/block-runtime/validation';
|
|
19
|
+
|
|
20
|
+
export const useTypiaValidation = createUseTypiaValidationHook( {
|
|
21
|
+
useMemo,
|
|
22
|
+
} );
|
|
23
|
+
`;
|
|
24
|
+
/**
|
|
25
|
+
* Template for the generated block metadata wrapper around `block.json`.
|
|
26
|
+
*/
|
|
27
|
+
export const BLOCK_METADATA_WRAPPER_TEMPLATE = `import rawMetadata from './block.json';
|
|
28
|
+
import { defineScaffoldBlockMetadata } from '@wp-typia/block-runtime/blocks';
|
|
29
|
+
|
|
30
|
+
const metadata = defineScaffoldBlockMetadata(rawMetadata);
|
|
31
|
+
|
|
32
|
+
export default metadata;
|
|
33
|
+
`;
|
|
34
|
+
/**
|
|
35
|
+
* Template for the generated manifest document wrapper around `typia.manifest.json`.
|
|
36
|
+
*/
|
|
37
|
+
export const MANIFEST_DOCUMENT_WRAPPER_TEMPLATE = `import rawCurrentManifest from './typia.manifest.json';
|
|
38
|
+
import { defineManifestDocument } from '@wp-typia/block-runtime/editor';
|
|
39
|
+
|
|
40
|
+
const currentManifest = defineManifestDocument(rawCurrentManifest);
|
|
41
|
+
|
|
42
|
+
export default currentManifest;
|
|
43
|
+
`;
|
|
44
|
+
/**
|
|
45
|
+
* Template for the generated manifest-defaults wrapper used by validators.
|
|
46
|
+
*/
|
|
47
|
+
export const MANIFEST_DEFAULTS_DOCUMENT_WRAPPER_TEMPLATE = `import rawCurrentManifest from './typia.manifest.json';
|
|
48
|
+
import { defineManifestDefaultsDocument } from '@wp-typia/block-runtime/defaults';
|
|
49
|
+
|
|
50
|
+
const currentManifest = defineManifestDefaultsDocument(rawCurrentManifest);
|
|
51
|
+
|
|
52
|
+
export default currentManifest;
|
|
53
|
+
`;
|