@wp-playground/blueprints 0.1.40 → 0.1.42

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 (50) hide show
  1. package/index.cjs +133 -0
  2. package/index.d.ts +7 -0
  3. package/index.js +2081 -0
  4. package/lib/blueprint.d.ts +27 -0
  5. package/lib/compile.d.ts +37 -0
  6. package/lib/resources.d.ts +211 -0
  7. package/lib/steps/activate-plugin.d.ts +12 -0
  8. package/lib/steps/apply-wordpress-patches/index.d.ts +12 -0
  9. package/lib/steps/client-methods.d.ts +56 -0
  10. package/lib/steps/common.d.ts +7 -0
  11. package/lib/steps/define-site-url.d.ts +12 -0
  12. package/lib/steps/define-wp-config-consts.d.ts +12 -0
  13. package/{src/lib/steps/handlers.ts → lib/steps/handlers.d.ts} +1 -12
  14. package/lib/steps/import-export.d.ts +67 -0
  15. package/lib/steps/index.d.ts +26 -0
  16. package/lib/steps/install-plugin.d.ts +22 -0
  17. package/lib/steps/install-theme.d.ts +22 -0
  18. package/lib/steps/login.d.ts +16 -0
  19. package/lib/steps/migration.d.ts +2 -0
  20. package/lib/steps/run-wp-installation-wizard.d.ts +16 -0
  21. package/lib/steps/site-data.d.ts +12 -0
  22. package/package.json +4 -3
  23. package/.eslintrc.json +0 -18
  24. package/LICENSE +0 -339
  25. package/README.md +0 -11
  26. package/project.json +0 -58
  27. package/src/index.ts +0 -31
  28. package/src/lib/blueprint.ts +0 -28
  29. package/src/lib/compile.spec.ts +0 -34
  30. package/src/lib/compile.ts +0 -262
  31. package/src/lib/resources.ts +0 -417
  32. package/src/lib/steps/activate-plugin.ts +0 -35
  33. package/src/lib/steps/apply-wordpress-patches/index.ts +0 -113
  34. package/src/lib/steps/apply-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php +0 -15
  35. package/src/lib/steps/client-methods.ts +0 -121
  36. package/src/lib/steps/common.ts +0 -30
  37. package/src/lib/steps/define-site-url.ts +0 -25
  38. package/src/lib/steps/define-wp-config-consts.ts +0 -45
  39. package/src/lib/steps/import-export.ts +0 -225
  40. package/src/lib/steps/index.ts +0 -67
  41. package/src/lib/steps/install-plugin.ts +0 -145
  42. package/src/lib/steps/install-theme.ts +0 -99
  43. package/src/lib/steps/login.ts +0 -37
  44. package/src/lib/steps/migration.ts +0 -63
  45. package/src/lib/steps/run-wp-installation-wizard.ts +0 -38
  46. package/src/lib/steps/site-data.ts +0 -58
  47. package/tsconfig.json +0 -23
  48. package/tsconfig.lib.json +0 -10
  49. package/tsconfig.spec.json +0 -19
  50. package/vite.config.ts +0 -58
@@ -1,113 +0,0 @@
1
- import { UniversalPHP } from '@php-wasm/universal';
2
- import { StepHandler } from '..';
3
- import { updateFile } from '../common';
4
-
5
- export interface ApplyWordPressPatchesStep {
6
- step: 'applyWordPressPatches';
7
- siteUrl: string;
8
- wordpressPath?: string;
9
- patchSqlitePlugin?: boolean;
10
- addPhpInfo?: boolean;
11
- patchSiteUrl?: boolean;
12
- disableSiteHealth?: boolean;
13
- disableWpNewBlogNotification?: boolean;
14
- }
15
-
16
- export const applyWordPressPatches: StepHandler<
17
- ApplyWordPressPatchesStep
18
- > = async (php, options) => {
19
- const patch = new WordPressPatcher(
20
- php,
21
- options.siteUrl,
22
- options.wordpressPath || '/wordpress'
23
- );
24
-
25
- if (options.patchSqlitePlugin !== false) {
26
- await patch.patchSqlitePlugin();
27
- }
28
- if (options.addPhpInfo !== false) {
29
- await patch.addPhpInfo();
30
- }
31
- if (options.patchSiteUrl !== false) {
32
- await patch.patchSiteUrl();
33
- }
34
- if (options.disableSiteHealth !== false) {
35
- await patch.disableSiteHealth();
36
- }
37
- if (options.disableWpNewBlogNotification !== false) {
38
- await patch.disableWpNewBlogNotification();
39
- }
40
- };
41
-
42
- class WordPressPatcher {
43
- php: UniversalPHP;
44
- scopedSiteUrl: string;
45
- wordpressPath: string;
46
-
47
- constructor(
48
- php: UniversalPHP,
49
- scopedSiteUrl: string,
50
- wordpressPath: string
51
- ) {
52
- this.php = php;
53
- this.scopedSiteUrl = scopedSiteUrl;
54
- this.wordpressPath = wordpressPath;
55
- }
56
-
57
- async patchSqlitePlugin() {
58
- // Upstream change proposed in https://github.com/WordPress/sqlite-database-integration/pull/28:
59
- await updateFile(
60
- this.php,
61
- `${this.wordpressPath}/wp-content/plugins/sqlite-database-integration/wp-includes/sqlite/class-wp-sqlite-translator.php`,
62
- (contents) => {
63
- return contents.replace(
64
- 'if ( false === strtotime( $value ) )',
65
- 'if ( $value === "0000-00-00 00:00:00" || false === strtotime( $value ) )'
66
- );
67
- }
68
- );
69
- }
70
-
71
- async addPhpInfo() {
72
- await this.php.writeFile(
73
- `${this.wordpressPath}/phpinfo.php`,
74
- '<?php phpinfo(); '
75
- );
76
- }
77
-
78
- async patchSiteUrl() {
79
- await updateFile(
80
- this.php,
81
- `${this.wordpressPath}/wp-config.php`,
82
- (contents) =>
83
- `<?php
84
- if(!defined('WP_HOME')) {
85
- define('WP_HOME', "${this.scopedSiteUrl}");
86
- define('WP_SITEURL', "${this.scopedSiteUrl}");
87
- }
88
- ?>${contents}`
89
- );
90
- }
91
-
92
- async disableSiteHealth() {
93
- await updateFile(
94
- this.php,
95
- `${this.wordpressPath}/wp-includes/default-filters.php`,
96
- (contents) =>
97
- contents.replace(
98
- /add_filter[^;]+wp_maybe_grant_site_health_caps[^;]+;/i,
99
- ''
100
- )
101
- );
102
- }
103
-
104
- async disableWpNewBlogNotification() {
105
- await updateFile(
106
- this.php,
107
- `${this.wordpressPath}/wp-config.php`,
108
- // The original version of this function crashes WASM PHP, let's define an empty one instead.
109
- (contents) =>
110
- `${contents} function wp_new_blog_notification(...$args){} `
111
- );
112
- }
113
- }
@@ -1,15 +0,0 @@
1
- <?php
2
- /**
3
- * Add a notice to wp-login.php offering the username and password.
4
- */
5
-
6
- add_action(
7
- 'login_message',
8
- function() {
9
- return <<<EOT
10
- <div class="message info">
11
- <strong>username:</strong> <code>admin</code><br /><strong>password</strong>: <code>password</code>
12
- </div>
13
- EOT;
14
- }
15
- );
@@ -1,121 +0,0 @@
1
- import { PHPRunOptions, PHPRequest } from '@php-wasm/universal';
2
- import { StepHandler } from '.';
3
- import { fileToUint8Array } from './common';
4
-
5
- export interface RunPHPStep {
6
- step: 'runPHP';
7
- code: string;
8
- }
9
-
10
- export const runPHP: StepHandler<RunPHPStep> = async (playground, { code }) => {
11
- return await playground.run({ code });
12
- };
13
-
14
- export interface RunPHPWithOptionsStep {
15
- step: 'runPHPWithOptions';
16
- options: PHPRunOptions;
17
- }
18
-
19
- export const runPHPWithOptions: StepHandler<RunPHPWithOptionsStep> = async (
20
- playground,
21
- { options }
22
- ) => {
23
- return await playground.run(options);
24
- };
25
-
26
- export interface SetPhpIniEntryStep {
27
- step: 'setPhpIniEntry';
28
- key: string;
29
- value: string;
30
- }
31
-
32
- export const setPhpIniEntry: StepHandler<SetPhpIniEntryStep> = async (
33
- playground,
34
- { key, value }
35
- ) => {
36
- await playground.setPhpIniEntry(key, value);
37
- };
38
-
39
- export interface RequestStep {
40
- step: 'request';
41
- request: PHPRequest;
42
- }
43
-
44
- export const request: StepHandler<RequestStep> = async (
45
- playground,
46
- { request }
47
- ) => {
48
- return await playground.request(request);
49
- };
50
-
51
- export interface CpStep {
52
- step: 'cp';
53
- fromPath: string;
54
- toPath: string;
55
- }
56
-
57
- export const cp: StepHandler<CpStep> = async (
58
- playground,
59
- { fromPath, toPath }
60
- ) => {
61
- await playground.writeFile(
62
- toPath,
63
- await playground.readFileAsBuffer(fromPath)
64
- );
65
- };
66
-
67
- export interface MvStep {
68
- step: 'mv';
69
- fromPath: string;
70
- toPath: string;
71
- }
72
-
73
- export const mv: StepHandler<MvStep> = async (
74
- playground,
75
- { fromPath, toPath }
76
- ) => {
77
- await playground.mv(fromPath, toPath);
78
- };
79
-
80
- export interface MkdirStep {
81
- step: 'mkdir';
82
- path: string;
83
- }
84
-
85
- export const mkdir: StepHandler<MkdirStep> = async (playground, { path }) => {
86
- await playground.mkdir(path);
87
- };
88
-
89
- export interface RmStep {
90
- step: 'rm';
91
- path: string;
92
- }
93
-
94
- export const rm: StepHandler<RmStep> = async (playground, { path }) => {
95
- await playground.unlink(path);
96
- };
97
-
98
- export interface RmdirStep {
99
- step: 'rmdir';
100
- path: string;
101
- }
102
-
103
- export const rmdir: StepHandler<RmdirStep> = async (playground, { path }) => {
104
- await playground.rmdir(path);
105
- };
106
-
107
- export interface WriteFileStep<ResourceType> {
108
- step: 'writeFile';
109
- path: string;
110
- data: ResourceType | string | Uint8Array;
111
- }
112
-
113
- export const writeFile: StepHandler<WriteFileStep<File>> = async (
114
- playground,
115
- { path, data }
116
- ) => {
117
- if (data instanceof File) {
118
- data = await fileToUint8Array(data);
119
- }
120
- await playground.writeFile(path, data);
121
- };
@@ -1,30 +0,0 @@
1
- import type { PHPResponse, UniversalPHP } from '@php-wasm/universal';
2
-
3
- export function asDOM(response: PHPResponse) {
4
- return new DOMParser().parseFromString(response.text, 'text/html')!;
5
- }
6
-
7
- export function zipNameToHumanName(zipName: string) {
8
- const mixedCaseName = zipName.split('.').shift()!.replace('-', ' ');
9
- return (
10
- mixedCaseName.charAt(0).toUpperCase() +
11
- mixedCaseName.slice(1).toLowerCase()
12
- );
13
- }
14
-
15
- type PatchFileCallback = (contents: string) => string | Uint8Array;
16
- export async function updateFile(
17
- php: UniversalPHP,
18
- path: string,
19
- callback: PatchFileCallback
20
- ) {
21
- let contents = '';
22
- if (await php.fileExists(path)) {
23
- contents = await php.readFileAsText(path);
24
- }
25
- await php.writeFile(path, callback(contents));
26
- }
27
-
28
- export async function fileToUint8Array(file: File) {
29
- return new Uint8Array(await file.arrayBuffer());
30
- }
@@ -1,25 +0,0 @@
1
- import { StepHandler } from '.';
2
- import { defineWpConfigConsts } from './define-wp-config-consts';
3
-
4
- export interface DefineSiteUrlStep {
5
- step: 'defineSiteUrl';
6
- siteUrl: string;
7
- }
8
-
9
- /**
10
- * Sets site URL of the WordPress installation.
11
- *
12
- * @param playground The playground client.
13
- * @param siteUrl
14
- */
15
- export const defineSiteUrl: StepHandler<DefineSiteUrlStep> = async (
16
- playground,
17
- { siteUrl }
18
- ) => {
19
- return await defineWpConfigConsts(playground, {
20
- consts: {
21
- WP_HOME: siteUrl,
22
- WP_SITEURL: siteUrl,
23
- },
24
- });
25
- };
@@ -1,45 +0,0 @@
1
- import { StepHandler } from '.';
2
- import { updateFile } from './common';
3
-
4
- export interface DefineWpConfigConstsStep {
5
- step: 'defineWpConfigConsts';
6
- consts: Record<string, unknown>;
7
- }
8
-
9
- /**
10
- * Sets site URL of the WordPress installation.
11
- *
12
- * @param playground The playground client.
13
- * @param wpConfigConst
14
- */
15
- export const defineWpConfigConsts: StepHandler<
16
- DefineWpConfigConstsStep
17
- > = async (playground, { consts }) => {
18
- const documentRoot = await playground.documentRoot;
19
- await updateFile(
20
- playground,
21
- `${documentRoot}/playground-consts.json`,
22
- (contents) =>
23
- JSON.stringify({
24
- ...JSON.parse(contents || '{}'),
25
- ...consts,
26
- })
27
- );
28
- await updateFile(
29
- playground,
30
- `${documentRoot}/wp-config.php`,
31
- (contents) => {
32
- if (!contents.includes('playground-consts.json')) {
33
- return `<?php
34
- $consts = json_decode(file_get_contents('./playground-consts.json'), true);
35
- foreach ($consts as $const => $value) {
36
- if (!defined($const)) {
37
- define($const, $value);
38
- }
39
- }
40
- ?>${contents}`;
41
- }
42
- return contents;
43
- }
44
- );
45
- };
@@ -1,225 +0,0 @@
1
- import { PHPResponse, UniversalPHP } from '@php-wasm/universal';
2
- import { phpVars } from '@php-wasm/util';
3
- import { StepHandler } from '.';
4
-
5
- // @ts-ignore
6
- import migrationsPHPCode from './migration';
7
-
8
- /**
9
- * Full site export support:
10
- */
11
-
12
- /**
13
- * Export the current site as a zip file.
14
- *
15
- * @param playground Playground client.
16
- */
17
- export async function zipEntireSite(playground: UniversalPHP) {
18
- const zipName = `wordpress-playground.zip`;
19
- const zipPath = `/${zipName}`;
20
-
21
- const js = phpVars({
22
- zipPath,
23
- documentRoot: await playground.documentRoot,
24
- });
25
- await phpMigration(
26
- playground,
27
- `zipDir(${js.documentRoot}, ${js.zipPath});`
28
- );
29
-
30
- const fileBuffer = await playground.readFileAsBuffer(zipPath);
31
- playground.unlink(zipPath);
32
-
33
- return new File([fileBuffer], zipName);
34
- }
35
-
36
- export interface ReplaceSiteStep<ResourceType> {
37
- step: 'replaceSite';
38
- fullSiteZip: ResourceType;
39
- }
40
-
41
- /**
42
- * Replace the current site with the contents of a full site zip file.
43
- *
44
- * @param playground Playground client.
45
- * @param fullSiteZip Zipped WordPress site.
46
- */
47
- export const replaceSite: StepHandler<ReplaceSiteStep<File>> = async (
48
- playground,
49
- { fullSiteZip }
50
- ) => {
51
- const zipPath = '/import.zip';
52
- await playground.writeFile(
53
- zipPath,
54
- new Uint8Array(await fullSiteZip.arrayBuffer())
55
- );
56
-
57
- const absoluteUrl = await playground.absoluteUrl;
58
- const documentRoot = await playground.documentRoot;
59
-
60
- await playground.rmdir(documentRoot);
61
- await unzip(playground, { zipPath, extractToPath: '/' });
62
-
63
- const js = phpVars({ absoluteUrl });
64
- await updateFile(
65
- playground,
66
- `${documentRoot}/wp-config.php`,
67
- (contents) =>
68
- `<?php
69
- if(!defined('WP_HOME')) {
70
- define('WP_HOME', ${js.absoluteUrl});
71
- define('WP_SITEURL', ${js.absoluteUrl});
72
- }
73
- ?>${contents}`
74
- );
75
- };
76
-
77
- export interface UnzipStep {
78
- step: 'unzip';
79
- zipPath: string;
80
- extractToPath: string;
81
- }
82
-
83
- /**
84
- * Unzip a zip file.
85
- *
86
- * @param playground Playground client.
87
- * @param zipPath The zip file to unzip.
88
- * @param extractTo The directory to extract the zip file to.
89
- */
90
- export const unzip: StepHandler<UnzipStep> = async (
91
- playground,
92
- { zipPath, extractToPath }
93
- ) => {
94
- const js = phpVars({
95
- zipPath,
96
- extractToPath,
97
- });
98
- await phpMigration(
99
- playground,
100
- `unzip(${js.zipPath}, ${js.extractToPath});`
101
- );
102
- };
103
-
104
- /**
105
- * WXR and WXZ files support:
106
- */
107
-
108
- /**
109
- * Exports the WordPress database as a WXR file using
110
- * the core WordPress export tool.
111
- *
112
- * @param playground Playground client
113
- * @returns WXR file
114
- */
115
- export async function exportWXR(playground: UniversalPHP) {
116
- const databaseExportResponse = await playground.request({
117
- url: '/wp-admin/export.php?download=true&content=all',
118
- });
119
- return new File([databaseExportResponse.bytes], 'export.xml');
120
- }
121
-
122
- /**
123
- * Exports the WordPress database as a WXZ file using
124
- * the export-wxz plugin from https://github.com/akirk/export-wxz.
125
- *
126
- * @param playground Playground client
127
- * @returns WXZ file
128
- */
129
- export async function exportWXZ(playground: UniversalPHP) {
130
- const databaseExportResponse = await playground.request({
131
- url: '/wp-admin/export.php?download=true&content=all&export_wxz=1',
132
- });
133
- return new File([databaseExportResponse.bytes], 'export.wxz');
134
- }
135
-
136
- export interface ImportFileStep<ResourceType> {
137
- step: 'importFile';
138
- file: ResourceType;
139
- }
140
-
141
- /**
142
- * Uploads a file to the WordPress importer and returns the response.
143
- * Supports both WXR and WXZ files.
144
- *
145
- * @see https://github.com/WordPress/wordpress-importer/compare/master...akirk:wordpress-importer:import-wxz.patch
146
- * @param playground Playground client.
147
- * @param file The file to import.
148
- */
149
- export const importFile: StepHandler<ImportFileStep<File>> = async (
150
- playground,
151
- { file }
152
- ) => {
153
- const importerPageOneResponse = await playground.request({
154
- url: '/wp-admin/admin.php?import=wordpress',
155
- });
156
-
157
- const firstUrlAction = DOM(importerPageOneResponse)
158
- .getElementById('import-upload-form')
159
- ?.getAttribute('action');
160
-
161
- const stepOneResponse = await playground.request({
162
- url: `/wp-admin/${firstUrlAction}`,
163
- method: 'POST',
164
- files: { import: file },
165
- });
166
-
167
- // Map authors of imported posts to existing users
168
- const importForm = DOM(stepOneResponse).querySelector(
169
- '#wpbody-content form'
170
- ) as HTMLFormElement;
171
-
172
- if (!importForm) {
173
- console.log(stepOneResponse.text);
174
- throw new Error(
175
- 'Could not find an importer form in response. See the response text above for details.'
176
- );
177
- }
178
-
179
- const data = getFormData(importForm);
180
- data['fetch_attachments'] = '1';
181
- for (const key in data) {
182
- if (key.startsWith('user_map[')) {
183
- const newKey = 'user_new[' + key.slice(9, -1) + ']';
184
- data[newKey] = '1'; // Hardcoded admin ID for now
185
- }
186
- }
187
-
188
- await playground.request({
189
- url: importForm.action,
190
- method: 'POST',
191
- formData: data,
192
- });
193
- };
194
-
195
- function DOM(response: PHPResponse) {
196
- return new DOMParser().parseFromString(response.text, 'text/html');
197
- }
198
-
199
- function getFormData(form: HTMLFormElement): Record<string, unknown> {
200
- return Object.fromEntries((new FormData(form) as any).entries());
201
- }
202
-
203
- async function updateFile(
204
- playground: UniversalPHP,
205
- path: string,
206
- callback: (contents: string) => string
207
- ) {
208
- await playground.writeFile(
209
- path,
210
- callback(await playground.readFileAsText(path))
211
- );
212
- }
213
-
214
- async function phpMigration(playground: UniversalPHP, code: string) {
215
- const result = await playground.run({
216
- code: migrationsPHPCode + code,
217
- });
218
- if (result.exitCode !== 0) {
219
- console.log(migrationsPHPCode + code);
220
- console.log(code + '');
221
- console.log(result.errors);
222
- throw result.errors;
223
- }
224
- return result;
225
- }
@@ -1,67 +0,0 @@
1
- import { ProgressTracker } from '@php-wasm/progress';
2
- import { UniversalPHP } from '@php-wasm/universal';
3
- import { FileReference } from '../resources';
4
- import { ActivatePluginStep } from './activate-plugin';
5
- import { ApplyWordPressPatchesStep } from './apply-wordpress-patches';
6
- import { DefineSiteUrlStep } from './define-site-url';
7
- import { ImportFileStep, ReplaceSiteStep, UnzipStep } from './import-export';
8
- import { InstallPluginStep } from './install-plugin';
9
- import { InstallThemeStep } from './install-theme';
10
- import { LoginStep } from './login';
11
- import { RunWpInstallationWizardStep } from './run-wp-installation-wizard';
12
- import { SetSiteOptionsStep, UpdateUserMetaStep } from './site-data';
13
- import {
14
- RmStep,
15
- CpStep,
16
- MkdirStep,
17
- RmdirStep,
18
- MvStep,
19
- SetPhpIniEntryStep,
20
- RunPHPStep,
21
- RunPHPWithOptionsStep,
22
- RequestStep,
23
- WriteFileStep,
24
- } from './client-methods';
25
- import { DefineWpConfigConstsStep } from './define-wp-config-consts';
26
-
27
- export type Step = GenericStep<FileReference>;
28
- export type StepDefinition = Step & {
29
- progress?: {
30
- weight?: number;
31
- caption?: string;
32
- };
33
- };
34
-
35
- export type GenericStep<Resource> =
36
- | ActivatePluginStep
37
- | ApplyWordPressPatchesStep
38
- | CpStep
39
- | DefineWpConfigConstsStep
40
- | DefineSiteUrlStep
41
- | ImportFileStep<Resource>
42
- | InstallPluginStep<Resource>
43
- | InstallThemeStep<Resource>
44
- | LoginStep
45
- | MkdirStep
46
- | MvStep
47
- | RequestStep
48
- | ReplaceSiteStep<Resource>
49
- | RmStep
50
- | RmdirStep
51
- | RunPHPStep
52
- | RunPHPWithOptionsStep
53
- | RunWpInstallationWizardStep
54
- | SetPhpIniEntryStep
55
- | SetSiteOptionsStep
56
- | UnzipStep
57
- | UpdateUserMetaStep
58
- | WriteFileStep<Resource>;
59
-
60
- export type StepHandler<S extends GenericStep<File>> = (
61
- php: UniversalPHP,
62
- args: Omit<S, 'step'>,
63
- progressArgs?: {
64
- tracker: ProgressTracker;
65
- initialCaption?: string;
66
- }
67
- ) => any;