export declare const PERSISTENCE_EDIT_TEMPLATE = "import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';\nimport { __ } from '@wordpress/i18n';\nimport {\n AlignmentToolbar,\n BlockControls,\n InspectorControls,\n RichText,\n store as blockEditorStore,\n useBlockProps,\n} from '@wordpress/block-editor';\nimport { Notice, PanelBody, TextControl } from '@wordpress/components';\nimport { useSelect } from '@wordpress/data';\nimport currentManifest from './manifest-document';\nimport {\n InspectorFromManifest,\n type PersistentBlockIdentityNode,\n useEditorFields,\n usePersistentBlockIdentity,\n useTypedAttributeUpdater,\n} from '@wp-typia/block-runtime/inspector';\nimport type { {{pascalCase}}Attributes } from './types';\nimport {\n sanitize{{pascalCase}}Attributes,\n validate{{pascalCase}}Attributes,\n} from './validators';\nimport { useTypiaValidation } from './hooks';\n\ntype EditProps = BlockEditProps<{{pascalCase}}Attributes>;\n\nexport default function Edit({\n attributes,\n clientId,\n setAttributes,\n}: EditProps) {\n const blocks = useSelect(\n (select) =>\n (\n select(blockEditorStore) as unknown as {\n getBlocks: () => readonly PersistentBlockIdentityNode[];\n }\n ).getBlocks(),\n [],\n );\n usePersistentBlockIdentity({\n attributeName: 'resourceKey',\n attributes,\n blockName: '{{namespace}}/{{slugKebabCase}}',\n blocks,\n clientId,\n prefix: '{{resourceKeyPrefix}}',\n setAttributes,\n });\n const editorFields = useEditorFields(currentManifest, {\n manual: ['content', 'resourceKey'],\n labels: {\n{{persistenceEditorFieldLabels}}\n },\n });\n const { errorMessages, isValid } = useTypiaValidation(\n attributes,\n validate{{pascalCase}}Attributes,\n );\n const validateEditorUpdate = (\n nextAttributes: {{pascalCase}}Attributes,\n ) => {\n try {\n return {\n{{persistenceSanitizeAttributesCall}}\n errors: [],\n isValid: true as const,\n };\n } catch {\n{{persistenceValidateAttributesCall}}\n }\n };\n const { updateField } = useTypedAttributeUpdater(\n attributes,\n setAttributes,\n validateEditorUpdate,\n );\n const alignmentValue = editorFields.getStringValue(\n attributes,\n 'alignment',\n 'left',\n );\n const persistencePolicy = '{{persistencePolicy}}';\n const persistencePolicyDescription = __(\n {{persistencePolicyDescriptionTsLiteral}},\n '{{textDomain}}',\n );\n\n return (\n <>\n \n \n updateField(\n 'alignment',\n (value || alignmentValue) as NonNullable<\n {{pascalCase}}Attributes['alignment']\n >,\n )\n }\n />\n \n \n \n updateField('resourceKey', value)}\n help={__(\n 'Stable persisted identifier used by the storage-backed counter endpoint.',\n '{{textDomain}}',\n )}\n />\n \n {__(\n 'Storage mode: {{dataStorageMode}}',\n '{{textDomain}}',\n )}\n \n \n {__(\n 'Persistence policy: {{persistencePolicy}}',\n '{{textDomain}}',\n )}\n
\n {persistencePolicyDescription}\n
\n \n {__(\n 'Render mode: dynamic. `render.php` bootstraps durable post context, while fresh session-only write data is loaded from the dedicated `/bootstrap` endpoint after hydration.',\n '{{textDomain}}',\n )}\n \n \n {!isValid && (\n \n {errorMessages.map((error, index) => (\n \n {error}\n \n ))}\n \n )}\n
\n ,\n },\n })}\n >\n updateField('content', value)}\n placeholder={__(\n {{titleTsLiteral}} + ' persistence block',\n '{{textDomain}}',\n )}\n />\n

\n {__('Resource key:', '{{textDomain}}')}{' '}\n {attributes.resourceKey || '\u2014'}\n

\n

\n {__('Storage mode:', '{{textDomain}}')} {{dataStorageMode}}\n

\n

\n {__('Persistence policy:', '{{textDomain}}')}{' '}\n {{persistencePolicy}}\n

\n {!isValid && (\n \n
    \n {errorMessages.map((error, index) => (\n
  • {error}
  • \n ))}\n
\n
\n )}\n \n \n );\n}\n"; export declare const PERSISTENCE_INDEX_TEMPLATE = "import {\n registerScaffoldBlockType,\n type BlockConfiguration,\n} from '@wp-typia/block-types/blocks/registration';\nimport {\n buildScaffoldBlockRegistration,\n parseScaffoldBlockMetadata,\n} from '@wp-typia/block-runtime/blocks';\n\nimport Edit from './edit';\nimport Save from './save';\nimport metadata from './block-metadata';\nimport './style.scss';\n\nimport type { {{pascalCase}}Attributes } from './types';\n\nconst registration = buildScaffoldBlockRegistration(\n parseScaffoldBlockMetadata<\n BlockConfiguration<{{pascalCase}}Attributes>\n >(metadata),\n {\n edit: Edit,\n save: Save,\n },\n);\n\nregisterScaffoldBlockType(registration.name, registration.settings);\n"; export declare const PERSISTENCE_SAVE_TEMPLATE = "export default function Save() {\n // This block is intentionally server-rendered. PHP bootstraps post context,\n // storage-backed state, and write-policy data before the frontend hydrates.\n return null;\n}\n"; export declare const PERSISTENCE_VALIDATORS_TEMPLATE = "import typia from 'typia';\nimport currentManifest from './manifest-defaults-document';\n{{validationTypesImport}}\nimport { generateResourceKey } from '@wp-typia/block-runtime/identifiers';\nimport { createTemplateValidatorToolkit } from './validator-toolkit';\n\nconst scaffoldValidators =\n createTemplateValidatorToolkit<{{pascalCase}}Attributes>({\n assert: typia.createAssert<{{pascalCase}}Attributes>(),\n clone: typia.plain.createClone<{{pascalCase}}Attributes>() as (\n value: {{pascalCase}}Attributes,\n ) => {{pascalCase}}Attributes,\n is: typia.createIs<{{pascalCase}}Attributes>(),\n manifest: currentManifest,\n prune: typia.plain.createPrune<{{pascalCase}}Attributes>(),\n random: typia.createRandom<{{pascalCase}}Attributes>() as (\n ...args: unknown[]\n ) => {{pascalCase}}Attributes,\n finalize: (normalized) => ({\n ...normalized,\n resourceKey:\n normalized.resourceKey && normalized.resourceKey.length > 0\n ? normalized.resourceKey\n : generateResourceKey('{{resourceKeyPrefix}}'),\n }),\n validate: typia.createValidate<{{pascalCase}}Attributes>(),\n });\n\nexport const validators = scaffoldValidators.validators;\n\nexport const validate{{pascalCase}}Attributes =\n scaffoldValidators.validateAttributes as (\n attributes: unknown,\n ) => {{pascalCase}}ValidationResult;\n\nexport const sanitize{{pascalCase}}Attributes =\n scaffoldValidators.sanitizeAttributes as (\n attributes: Partial<{{pascalCase}}Attributes>,\n ) => {{pascalCase}}Attributes;\n\nexport const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;\n"; export declare const PERSISTENCE_INTERACTIVITY_TEMPLATE = "import { getContext, store } from '@wordpress/interactivity';\nimport { generatePublicWriteRequestId } from '@wp-typia/block-runtime/identifiers';\n\nimport { fetchBootstrap, fetchState, writeState } from './api';\n{{persistenceTypesImport}}\nimport type { {{pascalCase}}WriteStateRequest } from './api-types';\n\nfunction hasExpiredPublicWriteToken(expiresAt?: number): boolean {\n return (\n typeof expiresAt === 'number' &&\n expiresAt > 0 &&\n Date.now() >= expiresAt * 1000\n );\n}\n\nfunction getWriteBlockedMessage(\n context: {{pascalCase}}Context,\n): string {\n return context.persistencePolicy === 'authenticated'\n ? 'Sign in to persist this counter.'\n : 'Public writes are temporarily unavailable.';\n}\n\nconst BOOTSTRAP_MAX_ATTEMPTS = 3;\nconst BOOTSTRAP_RETRY_DELAYS_MS = [250, 500];\n\nasync function waitForBootstrapRetry(delayMs: number): Promise {\n await new Promise((resolve) => {\n setTimeout(resolve, delayMs);\n });\n}\n\nfunction getClientState(\n context: {{pascalCase}}Context,\n): {{pascalCase}}ClientState {\n if (context.client) {\n return context.client;\n }\n\n context.client = {\n bootstrapError: '',\n writeExpiry: 0,\n writeNonce: '',\n writeToken: '',\n };\n\n return context.client;\n}\n\nfunction clearBootstrapError(\n context: {{pascalCase}}Context,\n clientState: {{pascalCase}}ClientState,\n): void {\n if (context.error === clientState.bootstrapError) {\n context.error = '';\n }\n clientState.bootstrapError = '';\n}\n\nfunction setBootstrapError(\n context: {{pascalCase}}Context,\n clientState: {{pascalCase}}ClientState,\n message: string,\n): void {\n clientState.bootstrapError = message;\n context.error = message;\n}\n\nconst { actions, state } = store('{{slugKebabCase}}', {\n state: {\n isHydrated: false,\n } as {{pascalCase}}State,\n\n actions: {\n async loadState() {\n const context = getContext<{{pascalCase}}Context>();\n if (context.postId <= 0 || !context.resourceKey) {\n return;\n }\n\n context.isLoading = true;\n context.error = '';\n\n try {\n const result = await fetchState(\n {\n postId: context.postId,\n resourceKey: context.resourceKey,\n },\n {\n transportTarget: 'frontend',\n },\n );\n if (!result.isValid || !result.data) {\n context.error =\n result.errors[0]?.expected ?? 'Unable to load counter';\n return;\n }\n context.count = result.data.count;\n } catch (error) {\n context.error =\n error instanceof Error ? error.message : 'Unknown loading error';\n } finally {\n context.isLoading = false;\n }\n },\n async loadBootstrap() {\n const context = getContext<{{pascalCase}}Context>();\n const clientState = getClientState(context);\n if (context.postId <= 0 || !context.resourceKey) {\n context.bootstrapReady = true;\n context.canWrite = false;\n clientState.bootstrapError = '';\n clientState.writeExpiry = 0;\n clientState.writeNonce = '';\n clientState.writeToken = '';\n return;\n }\n\n context.isBootstrapping = true;\n\n let bootstrapSucceeded = false;\n let lastBootstrapError = 'Unable to initialize write access';\n const includePublicWriteCredentials = {{isPublicPersistencePolicy}};\n const includeRestNonce = {{isAuthenticatedPersistencePolicy}};\n\n for (let attempt = 1; attempt <= BOOTSTRAP_MAX_ATTEMPTS; attempt += 1) {\n try {\n const result = await fetchBootstrap(\n {\n postId: context.postId,\n resourceKey: context.resourceKey,\n },\n {\n transportTarget: 'frontend',\n },\n );\n if (!result.isValid || !result.data) {\n lastBootstrapError =\n result.errors[0]?.expected ?? 'Unable to initialize write access';\n if (attempt < BOOTSTRAP_MAX_ATTEMPTS) {\n await waitForBootstrapRetry(\n BOOTSTRAP_RETRY_DELAYS_MS[attempt - 1] ?? 750,\n );\n continue;\n }\n break;\n }\n\n clientState.writeExpiry =\n includePublicWriteCredentials &&\n 'publicWriteExpiresAt' in result.data &&\n typeof result.data.publicWriteExpiresAt === 'number' &&\n result.data.publicWriteExpiresAt > 0\n ? result.data.publicWriteExpiresAt\n : 0;\n clientState.writeToken =\n includePublicWriteCredentials &&\n 'publicWriteToken' in result.data &&\n typeof result.data.publicWriteToken === 'string' &&\n result.data.publicWriteToken.length > 0\n ? result.data.publicWriteToken\n : '';\n clientState.writeNonce =\n includeRestNonce &&\n 'restNonce' in result.data &&\n typeof result.data.restNonce === 'string' &&\n result.data.restNonce.length > 0\n ? result.data.restNonce\n : '';\n context.bootstrapReady = true;\n context.canWrite =\n result.data.canWrite === true &&\n (context.persistencePolicy === 'authenticated'\n ? clientState.writeNonce.length > 0\n : clientState.writeToken.length > 0 &&\n !hasExpiredPublicWriteToken(clientState.writeExpiry));\n clearBootstrapError(context, clientState);\n bootstrapSucceeded = true;\n break;\n } catch (error) {\n lastBootstrapError =\n error instanceof Error ? error.message : 'Unknown bootstrap error';\n if (attempt < BOOTSTRAP_MAX_ATTEMPTS) {\n await waitForBootstrapRetry(\n BOOTSTRAP_RETRY_DELAYS_MS[attempt - 1] ?? 750,\n );\n continue;\n }\n break;\n }\n }\n\n if (!bootstrapSucceeded) {\n context.bootstrapReady = false;\n context.canWrite = false;\n clientState.writeExpiry = 0;\n clientState.writeNonce = '';\n clientState.writeToken = '';\n setBootstrapError(context, clientState, lastBootstrapError);\n }\n context.isBootstrapping = false;\n },\n async increment() {\n const context = getContext<{{pascalCase}}Context>();\n const clientState = getClientState(context);\n if (context.postId <= 0 || !context.resourceKey) {\n return;\n }\n if (!context.bootstrapReady) {\n await actions.loadBootstrap();\n }\n if (!context.bootstrapReady) {\n context.error = 'Write access is still initializing.';\n return;\n }\n if (\n context.persistencePolicy === 'public' &&\n hasExpiredPublicWriteToken(clientState.writeExpiry)\n ) {\n await actions.loadBootstrap();\n }\n if (\n context.persistencePolicy === 'public' &&\n hasExpiredPublicWriteToken(clientState.writeExpiry)\n ) {\n context.canWrite = false;\n context.error = getWriteBlockedMessage(context);\n return;\n }\n if (!context.canWrite) {\n context.error = getWriteBlockedMessage(context);\n return;\n }\n\n context.isSaving = true;\n context.error = '';\n\n try {\n const request = {\n delta: 1,\n postId: context.postId,\n resourceKey: context.resourceKey,\n } as {{pascalCase}}WriteStateRequest;\n if ({{isPublicPersistencePolicy}}) {\n request.publicWriteRequestId =\n generatePublicWriteRequestId() as {{pascalCase}}WriteStateRequest['publicWriteRequestId'];\n if (clientState.writeToken.length > 0) {\n request.publicWriteToken =\n clientState.writeToken as {{pascalCase}}WriteStateRequest['publicWriteToken'];\n }\n }\n const result = await writeState(request, {\n restNonce:\n clientState.writeNonce.length > 0\n ? clientState.writeNonce\n : undefined,\n transportTarget: 'frontend',\n });\n if (!result.isValid || !result.data) {\n context.error =\n result.errors[0]?.expected ?? 'Unable to update counter';\n return;\n }\n context.count = result.data.count;\n context.storage = result.data.storage;\n } catch (error) {\n context.error =\n error instanceof Error ? error.message : 'Unknown update error';\n } finally {\n context.isSaving = false;\n }\n },\n },\n\n callbacks: {\n init() {\n const context = getContext<{{pascalCase}}Context>();\n context.client = {\n bootstrapError: '',\n writeExpiry: 0,\n writeNonce: '',\n writeToken: '',\n };\n context.bootstrapReady = false;\n context.canWrite = false;\n context.count = 0;\n context.error = '';\n context.isBootstrapping = false;\n context.isLoading = false;\n context.isSaving = false;\n },\n mounted() {\n state.isHydrated = true;\n if (typeof document !== 'undefined') {\n document.documentElement.dataset['{{slugCamelCase}}Hydrated'] =\n 'true';\n }\n void Promise.allSettled([actions.loadState(), actions.loadBootstrap()]);\n },\n },\n});\n";