@webx-ui/module-admin 0.27.0 → 0.28.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.
package/README.md CHANGED
@@ -132,6 +132,34 @@ try {
132
132
  }
133
133
  ```
134
134
 
135
+ ### A host that refuses PUT
136
+
137
+ Some shared hosting lets nothing but GET and POST past the web server: the panel opens and
138
+ reads, and every save or delete gets a 403 or 405 before PHP is reached. `methodOverride` sends
139
+ PUT, PATCH and DELETE as POST and says what they really are:
140
+
141
+ ```ts
142
+ createAdmin({
143
+ modules: [pages],
144
+ plugins: [auth()],
145
+ methodOverride: true, // or 'header', or 'field'
146
+ }).mount()
147
+ ```
148
+
149
+ | Value | On the wire |
150
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
151
+ | `false` (default) | Every method as it is |
152
+ | `true` or `'header'` | `POST` with `X-HTTP-Method-Override: PUT` |
153
+ | `'field'` | `POST` with `_method: "PUT"` in the JSON body, in a form, or in the query for raw bytes — for a firewall that strips the header too |
154
+
155
+ GET and POST are never touched, and the CSRF token goes with every overridden request as it
156
+ did before. Laravel reads both forms on its own; the server needs nothing. The option belongs
157
+ to the panel's own client — a project that passes its own `http` passes `methodOverride` to
158
+ `createHttp()` instead.
159
+
160
+ `php artisan webx:doctor` says whether the site's host is one of them: it sends a PUT and a
161
+ DELETE to its own `APP_URL` and warns when the web server, not Laravel, refuses them.
162
+
135
163
  `can('pages.manage')` answers from the signed-in session — a super administrator passes
136
164
  everything, the same rule the server applies.
137
165
 
@@ -1,7 +1,7 @@
1
1
  import { App, Component } from 'vue';
2
2
  import { Router, RouteRecordRaw } from 'vue-router';
3
3
  import { AdminContext } from './admin';
4
- import { Http } from './http';
4
+ import { Http, MethodOverride } from './http';
5
5
  import { I18n } from './i18n';
6
6
  import { ThemeController } from './theme';
7
7
  import { Patch, TypeRegistry } from '@webx-ui/schema';
@@ -52,6 +52,12 @@ export interface CreateAdminOptions {
52
52
  * key for writing: the server decides what is saved.
53
53
  */
54
54
  screens?: Record<string, Patch>;
55
+ /**
56
+ * Send PUT, PATCH and DELETE as POST, for a host whose web server refuses them before PHP is
57
+ * reached: `true` or `'header'` names the method in `X-HTTP-Method-Override`, `'field'` in
58
+ * a `_method` field of the body. Off by default; ignored when `http` is given.
59
+ */
60
+ methodOverride?: MethodOverride;
55
61
  /** Swappable for tests. */
56
62
  http?: Http;
57
63
  }
package/dist/http.d.ts CHANGED
@@ -22,7 +22,16 @@ export interface HttpOptions {
22
22
  headers?: () => Record<string, string>;
23
23
  /** Swappable for tests. */
24
24
  fetch?: typeof globalThis.fetch;
25
+ /**
26
+ * For a host whose web server lets through nothing but GET and POST, as some shared hosting
27
+ * does before PHP is even reached: PUT, PATCH and DELETE go out as POST and say what they
28
+ * really are. `'header'` (or `true`) says it in `X-HTTP-Method-Override`; `'field'` in a
29
+ * `_method` field, for a firewall that strips the header too. Laravel understands both.
30
+ */
31
+ methodOverride?: MethodOverride;
25
32
  }
33
+ /** How a method a web server refuses travels inside a POST; `true` is `'header'`. */
34
+ export type MethodOverride = boolean | 'header' | 'field';
26
35
  export interface RequestOptions {
27
36
  /** Query parameters; `undefined` and `null` are left out rather than sent empty. */
28
37
  query?: Record<string, string | number | boolean | null | undefined>;
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { createNotesApi, type EntityNote, type NoteAuthor, type NotesApi } from
15
15
  export { createHistoryApi, historySubjectKey, historyValue, provideHistorySubject, useHistorySubject, type HistoryApi, type HistoryChange, type HistoryEntry, type HistoryEvent, type HistoryPage, type HistoryRun, type HistorySource, type HistorySubject, } from './history';
16
16
  export { createLinksApi, emptyLink, type LinkCandidate, type LinkRel, type LinkSourceInfo, type LinkTarget, type LinkValue, type LinksApi, type ResolvedLink, } from './links';
17
17
  export { forgetShortcodes, loadShortcodes, shortcodeToken, useShortcodes, type Shortcode, type ShortcodeToken, } from './shortcodes';
18
- export { createHttp, readCookie, HttpError, type Http, type HttpOptions, type RequestOptions, type SendOptions, } from './http';
18
+ export { createHttp, readCookie, HttpError, type Http, type HttpOptions, type MethodOverride, type RequestOptions, type SendOptions, } from './http';
19
19
  export { forgetUnfinishedUpload, MIN_CHUNK, unfinishedUploads, uploadFingerprint, useChunkedUpload, type ChunkedUpload, type ChunkedUploadOptions, type ChunkedUploadState, type UnfinishedUpload, } from './uploads';
20
20
  export { adminTypes } from './screenTypes';
21
21
  export { categoryRoutes, categoryEditorKey, createCategoriesApi, itemOrderMode, provideCategoryEditor, reorderItems, useCategoryEditor, useCategoryWords, useItemOrder, type CategoriesApi, type CategoriesOptions, type CategoriesPayload, type CategoryDetail, type CategoryEditorContext, type CategoryRow, type CategoryWord, type ItemOrder, type ItemOrderMode, type ItemOrderState, } from './categories';