@wssto2/vue-core 0.5.3 → 0.5.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.4 — 2026-10-14
4
+
5
+ A route says what its envelope's `meta` is, so a paged list reads its numbers with no cast. Needed by go-core v1.8.7's route tables.
6
+
7
+ ### New
8
+ - **`route<In, Out, Meta = unknown>`** (and `ApiRoute<In, Out, Meta>`, `RouteResult<Out, Meta>`): a route can declare the type of go-core's top-level `meta`, and `client.request` resolves to `ApiResult<Out, Meta>`. A route without a meta type is unchanged (`meta: unknown`).
9
+ - **`PageMeta`** from `/client`: what go-core's `route.Page[T]` (`web.PageMeta`) writes: `total`, `page`, `per_page`, `last_page`, `from`, `to`, optional `views`, and any other key as `unknown`.
10
+ - **`readListPage`** accepts an `ApiResult<Row[], PageMeta>` with no cast.
11
+
3
12
  ## 0.5.3 — 2026-10-13
4
13
 
5
14
  The access rows on a phone.
@@ -38,7 +38,7 @@ export interface HttpClientOptions {
38
38
  /** A route that takes no input (`void`, or an empty object) needs no second argument. */
39
39
  type RequestArguments<In> = [In] extends [void] ? [input?: undefined, options?: RequestOptions] : [In] extends [Record<string, never>] ? [input?: In, options?: RequestOptions] : [input: In, options?: RequestOptions];
40
40
  /** A route declared `void` has no body: its data is `null`. */
41
- export type RouteResult<Out> = ApiResult<[Out] extends [void] ? null : Out>;
41
+ export type RouteResult<Out, Meta = unknown> = ApiResult<[Out] extends [void] ? null : Out, Meta>;
42
42
  export interface HttpClient {
43
43
  /**
44
44
  * Calls a declared route: `:name` segments of the path are filled from `input` (encoded), the rest of
@@ -46,7 +46,7 @@ export interface HttpClient {
46
46
  * parameter rejects with a plain `Error` (a bug in the caller, not an answer from the server) before
47
47
  * anything is sent. Abort, request ids and 401 handling are those of `get` and `post`.
48
48
  */
49
- request<In, Out>(route: ApiRoute<In, Out>, ...args: RequestArguments<In>): Promise<RouteResult<Out>>;
49
+ request<In, Out, Meta>(route: ApiRoute<In, Out, Meta>, ...args: RequestArguments<In>): Promise<RouteResult<Out, Meta>>;
50
50
  get<TData = unknown, TMeta = unknown>(path: string, options?: RequestOptions): Promise<ApiResult<TData, TMeta>>;
51
51
  post<TData = unknown, TMeta = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResult<TData, TMeta>>;
52
52
  put<TData = unknown, TMeta = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResult<TData, TMeta>>;
@@ -8,4 +8,4 @@ export type { ApiErrorInit, ApiErrorKind, FieldErrors } from "./error";
8
8
  export { fetchTransport } from "./transport";
9
9
  export type { Transport } from "./transport";
10
10
  export { route } from "./route";
11
- export type { HttpMethod, ListResult, RawRoute, ApiRoute, RouteOptions, ViewCount } from "./route";
11
+ export type { HttpMethod, ListResult, PageMeta, RawRoute, ApiRoute, RouteOptions, ViewCount } from "./route";
@@ -13,13 +13,18 @@ interface RouteBase {
13
13
  readonly permission?: string;
14
14
  readonly public: boolean;
15
15
  }
16
- /** A typed call: `In` is what `client.request` takes, `Out` what it resolves to (`void`: no body). */
17
- export interface ApiRoute<In, Out> extends RouteBase {
16
+ /**
17
+ * A typed call: `In` is what `client.request` takes, `Out` what it resolves to (`void`: no body), `Meta` the
18
+ * envelope's top-level `meta` (go-core `route.WithMeta` / `route.Page`). `Meta` defaults to `unknown`, not
19
+ * `never`: a route that declares none may still be answered with a meta, and `unknown` makes the caller narrow it.
20
+ */
21
+ export interface ApiRoute<In, Out, Meta = unknown> extends RouteBase {
18
22
  readonly raw: false;
19
23
  /** Type-only; never set. */
20
24
  readonly [types]?: {
21
25
  readonly in: In;
22
26
  readonly out: Out;
27
+ readonly meta: Meta;
23
28
  };
24
29
  }
25
30
  /** A route without a JSON answer (an event stream, a file): it keeps method and path for links, `client.request` refuses it. */
@@ -30,8 +35,9 @@ export interface RawRoute extends RouteBase {
30
35
  * Declares one endpoint. go-core's generator writes these; the types come from the Go input and response.
31
36
  *
32
37
  * route<ShowInput, Ticket>("GET", "/v1/tickets/:id", { permission: "tickets.ticket:view" })
38
+ * route<ListInput, Ticket[], PageMeta>("GET", "/v1/tickets") // a page: `result.meta` is a PageMeta
33
39
  */
34
- export declare function route<In, Out>(method: HttpMethod, path: string, options?: RouteOptions): ApiRoute<In, Out>;
40
+ export declare function route<In, Out, Meta = unknown>(method: HttpMethod, path: string, options?: RouteOptions): ApiRoute<In, Out, Meta>;
35
41
  export declare namespace route {
36
42
  var raw: (method: HttpMethod, path: string, options?: RouteOptions) => RawRoute;
37
43
  }
@@ -40,6 +46,19 @@ export interface ViewCount {
40
46
  readonly key: string;
41
47
  readonly count: number;
42
48
  }
49
+ /**
50
+ * The `meta` go-core's `web.PageMeta` writes next to a page of rows (`route.Page[T]`); other keys
51
+ * (lookups, totals) may sit beside these. `readListPage` reads an `ApiResult<Row[], PageMeta>` with no cast.
52
+ */
53
+ export type PageMeta = Readonly<Record<string, unknown>> & {
54
+ readonly total: number;
55
+ readonly page: number;
56
+ readonly per_page: number;
57
+ readonly last_page: number;
58
+ readonly from: number;
59
+ readonly to: number;
60
+ readonly views?: readonly ViewCount[];
61
+ };
43
62
  /**
44
63
  * The wire shape of go-core's `datatable.DatatableResult[T]`: a page of rows with its numbers.
45
64
  * `readListPage` (`/collection`) reads it into a `ListPage` with no glue.
@@ -1,4 +1,4 @@
1
- import type { ApiResult, HttpClient, ListResult, QueryValue } from "../client";
1
+ import type { ApiResult, HttpClient, ListResult, PageMeta, QueryValue } from "../client";
2
2
  import type { CollectionLoader, ListPage, CollectionQuery } from "./types";
3
3
  /**
4
4
  * The query parameters go-core's datatable reads: `page`, `per_page`, `order_col`, `order_dir`,
@@ -8,10 +8,11 @@ export declare function listParams(query: CollectionQuery): Record<string, Query
8
8
  /**
9
9
  * Reads a list answer into a `ListPage`. Understands go-core's envelope (`data` is the rows,
10
10
  * `meta` has `total`, `page`, `per_page`, `last_page`, `from`, `to`, and may carry `views` and lookups)
11
- * and the shape with the numbers next to `data` (`current_page`), which is `ListResult<Row>`: pass a typed
11
+ * and the shape with the numbers next to `data` (`current_page`), which is `ListResult<Row>`; a `route.Page` route answers `Row[]` with a `PageMeta`. Pass a typed
12
12
  * route's result (`client.request(route, input)`) and `Row` is inferred. Missing numbers are derived
13
13
  * from what is there rather than becoming 0; `query` supplies the page and size that were asked for.
14
14
  */
15
+ export declare function readListPage<Row>(result: ApiResult<readonly Row[], PageMeta>, query: Pick<CollectionQuery, "page" | "pageSize">): ListPage<Row>;
15
16
  export declare function readListPage<Row>(result: ApiResult<ListResult<Row>, unknown>, query: Pick<CollectionQuery, "page" | "pageSize">): ListPage<Row>;
16
17
  export declare function readListPage<Row>(result: ApiResult<unknown, unknown>, query: Pick<CollectionQuery, "page" | "pageSize">): ListPage<Row>;
17
18
  /**
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** The version of @wssto2/vue-core (kept equal to package.json by index.test.ts). */
2
- export declare const version = "0.5.3";
2
+ export declare const version = "0.5.4";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const o = "0.5.3";
1
+ const o = "0.5.4";
2
2
  export {
3
3
  o as version
4
4
  };
@@ -1,16 +1,16 @@
1
1
  import type { BindableRoles, Binding, Replaced, Role, RoleComparison, RoleHolders, RoleList, ScopeOptions, SubjectAccess } from "./entities";
2
2
  export declare const accessRoutes: {
3
- readonly rolesList: import("../../client").ApiRoute<void, RoleList>;
3
+ readonly rolesList: import("../../client").ApiRoute<void, RoleList, unknown>;
4
4
  readonly rolesShow: import("../../client").ApiRoute<{
5
5
  ref: string;
6
- }, Role>;
6
+ }, Role, unknown>;
7
7
  readonly rolesHolders: import("../../client").ApiRoute<{
8
8
  ref: string;
9
- }, RoleHolders>;
9
+ }, RoleHolders, unknown>;
10
10
  readonly rolesCompare: import("../../client").ApiRoute<{
11
11
  ref: string;
12
12
  with: string;
13
- }, RoleComparison>;
13
+ }, RoleComparison, unknown>;
14
14
  readonly rolesCreate: import("../../client").ApiRoute<{
15
15
  name: string;
16
16
  description: string;
@@ -22,7 +22,7 @@ export declare const accessRoutes: {
22
22
  attribute: string;
23
23
  values: string[];
24
24
  }[];
25
- }, Role>;
25
+ }, Role, unknown>;
26
26
  readonly rolesUpdate: import("../../client").ApiRoute<{
27
27
  ref: string;
28
28
  name: string;
@@ -35,33 +35,33 @@ export declare const accessRoutes: {
35
35
  attribute: string;
36
36
  values: string[];
37
37
  }[];
38
- }, Role>;
38
+ }, Role, unknown>;
39
39
  readonly rolesDelete: import("../../client").ApiRoute<{
40
40
  ref: string;
41
- }, void>;
41
+ }, void, unknown>;
42
42
  readonly rolesReplace: import("../../client").ApiRoute<{
43
43
  ref: string;
44
44
  with: string;
45
- }, Replaced>;
45
+ }, Replaced, unknown>;
46
46
  readonly bindable: import("../../client").ApiRoute<{
47
47
  level: string;
48
48
  scope_id: number;
49
- }, BindableRoles>;
49
+ }, BindableRoles, unknown>;
50
50
  readonly subjectsAccess: import("../../client").ApiRoute<{
51
51
  id: number;
52
- }, SubjectAccess>;
52
+ }, SubjectAccess, unknown>;
53
53
  readonly subjectsScopes: import("../../client").ApiRoute<{
54
54
  id: number;
55
- }, ScopeOptions>;
55
+ }, ScopeOptions, unknown>;
56
56
  readonly subjectsBind: import("../../client").ApiRoute<{
57
57
  id: number;
58
58
  role_ref: string;
59
59
  level: string;
60
60
  scope_id?: number | null | undefined;
61
- }, Binding>;
61
+ }, Binding, unknown>;
62
62
  readonly subjectsUnbind: import("../../client").ApiRoute<{
63
63
  id: number;
64
64
  binding_id: number;
65
- }, void>;
65
+ }, void, unknown>;
66
66
  readonly me: import("../../client").RawRoute;
67
67
  };
@@ -5,13 +5,13 @@ export declare const eventsRoutes: {
5
5
  consumer?: string | undefined;
6
6
  page?: number | undefined;
7
7
  per_page?: number | undefined;
8
- }, ListResult<DeadLetterRow>>;
8
+ }, ListResult<DeadLetterRow>, unknown>;
9
9
  readonly deadLettersRetry: import("../../client").ApiRoute<{
10
10
  event: number;
11
11
  consumer: string;
12
- }, Retried>;
12
+ }, Retried, unknown>;
13
13
  readonly deadLettersRetryAll: import("../../client").ApiRoute<{
14
14
  consumer: string;
15
- }, Retried>;
16
- readonly consumers: import("../../client").ApiRoute<void, ConsumerNames>;
15
+ }, Retried, unknown>;
16
+ readonly consumers: import("../../client").ApiRoute<void, ConsumerNames, unknown>;
17
17
  };
@@ -4,19 +4,19 @@ export declare const identityRoutes: {
4
4
  readonly login: import("../../client").ApiRoute<{
5
5
  login: string;
6
6
  password: string;
7
- }, SessionResponse>;
7
+ }, SessionResponse, unknown>;
8
8
  readonly refresh: import("../../client").ApiRoute<{
9
9
  refresh_token: string;
10
- }, SessionResponse>;
11
- readonly logout: import("../../client").ApiRoute<void, void>;
12
- readonly me: import("../../client").ApiRoute<void, SessionResponse>;
10
+ }, SessionResponse, unknown>;
11
+ readonly logout: import("../../client").ApiRoute<void, void, unknown>;
12
+ readonly me: import("../../client").ApiRoute<void, SessionResponse, unknown>;
13
13
  readonly changeLocale: import("../../client").ApiRoute<{
14
14
  locale: string;
15
- }, void>;
15
+ }, void, unknown>;
16
16
  readonly loginAs: import("../../client").ApiRoute<{
17
17
  user_id: number;
18
- }, SessionResponse>;
19
- readonly loginAsReturn: import("../../client").ApiRoute<void, SessionResponse>;
18
+ }, SessionResponse, unknown>;
19
+ readonly loginAsReturn: import("../../client").ApiRoute<void, SessionResponse, unknown>;
20
20
  readonly usersList: import("../../client").ApiRoute<{
21
21
  view?: "inactive" | "all" | "locked" | "active" | undefined;
22
22
  search?: string | undefined;
@@ -24,10 +24,10 @@ export declare const identityRoutes: {
24
24
  order_dir?: string | undefined;
25
25
  page?: number | undefined;
26
26
  per_page?: number | undefined;
27
- }, ListResult<UserRow>>;
27
+ }, ListResult<UserRow>, unknown>;
28
28
  readonly usersShow: import("../../client").ApiRoute<{
29
29
  id: number;
30
- }, UserDetail>;
30
+ }, UserDetail, unknown>;
31
31
  readonly usersCreate: import("../../client").ApiRoute<{
32
32
  login: string;
33
33
  name: string;
@@ -35,7 +35,7 @@ export declare const identityRoutes: {
35
35
  locale: string;
36
36
  password: string;
37
37
  phone?: string | undefined;
38
- }, UserDetail>;
38
+ }, UserDetail, unknown>;
39
39
  readonly usersUpdate: import("../../client").ApiRoute<{
40
40
  id: number;
41
41
  login: string;
@@ -43,32 +43,32 @@ export declare const identityRoutes: {
43
43
  email: string;
44
44
  locale: string;
45
45
  phone?: string | undefined;
46
- }, UserDetail>;
46
+ }, UserDetail, unknown>;
47
47
  readonly usersSetPassword: import("../../client").ApiRoute<{
48
48
  id: number;
49
49
  password: string;
50
- }, void>;
50
+ }, void, unknown>;
51
51
  readonly usersDeactivate: import("../../client").ApiRoute<{
52
52
  id: number;
53
- }, void>;
53
+ }, void, unknown>;
54
54
  readonly usersActivate: import("../../client").ApiRoute<{
55
55
  id: number;
56
- }, void>;
56
+ }, void, unknown>;
57
57
  readonly usersUnlock: import("../../client").ApiRoute<{
58
58
  id: number;
59
- }, UnlockResult>;
59
+ }, UnlockResult, unknown>;
60
60
  readonly usersSignins: import("../../client").ApiRoute<{
61
61
  id: number;
62
62
  view?: "all" | "failed" | undefined;
63
63
  page?: number | undefined;
64
64
  per_page?: number | undefined;
65
- }, ListResult<SignInRow>>;
65
+ }, ListResult<SignInRow>, unknown>;
66
66
  readonly usersChanges: import("../../client").ApiRoute<{
67
67
  id: number;
68
68
  view?: "details" | "all" | "access" | undefined;
69
69
  page?: number | undefined;
70
70
  per_page?: number | undefined;
71
- }, ListResult<ChangeRow>>;
71
+ }, ListResult<ChangeRow>, unknown>;
72
72
  readonly usersActivity: import("../../client").ApiRoute<{
73
73
  id: number;
74
74
  area?: string | undefined;
@@ -76,43 +76,43 @@ export declare const identityRoutes: {
76
76
  to?: string | undefined;
77
77
  page?: number | undefined;
78
78
  per_page?: number | undefined;
79
- }, ListResult<ActivityRow>>;
79
+ }, ListResult<ActivityRow>, unknown>;
80
80
  readonly usersSessions: import("../../client").ApiRoute<{
81
81
  id: number;
82
- }, SessionList>;
82
+ }, SessionList, unknown>;
83
83
  readonly usersRevokeSession: import("../../client").ApiRoute<{
84
84
  id: number;
85
85
  session_id: number;
86
- }, void>;
86
+ }, void, unknown>;
87
87
  readonly usersRevokeSessions: import("../../client").ApiRoute<{
88
88
  id: number;
89
- }, void>;
90
- readonly profileShow: import("../../client").ApiRoute<void, ProfileResponse>;
89
+ }, void, unknown>;
90
+ readonly profileShow: import("../../client").ApiRoute<void, ProfileResponse, unknown>;
91
91
  readonly profileUpdate: import("../../client").ApiRoute<{
92
92
  name: string;
93
93
  phone?: string | undefined;
94
- }, ProfileResponse>;
94
+ }, ProfileResponse, unknown>;
95
95
  readonly profileChangePassword: import("../../client").ApiRoute<{
96
96
  current_password: string;
97
97
  new_password: string;
98
98
  new_password_confirmation: string;
99
- }, void>;
99
+ }, void, unknown>;
100
100
  readonly profileRequestEmail: import("../../client").ApiRoute<{
101
101
  email: string;
102
102
  current_password: string;
103
- }, PendingEmail>;
104
- readonly profileResendEmail: import("../../client").ApiRoute<void, PendingEmail>;
103
+ }, PendingEmail, unknown>;
104
+ readonly profileResendEmail: import("../../client").ApiRoute<void, PendingEmail, unknown>;
105
105
  readonly profileConfirmEmail: import("../../client").ApiRoute<{
106
106
  code: string;
107
- }, ProfileResponse>;
108
- readonly profileCancelEmail: import("../../client").ApiRoute<void, void>;
107
+ }, ProfileResponse, unknown>;
108
+ readonly profileCancelEmail: import("../../client").ApiRoute<void, void, unknown>;
109
109
  readonly profileSignins: import("../../client").ApiRoute<{
110
110
  view?: "all" | "failed" | undefined;
111
111
  page?: number | undefined;
112
112
  per_page?: number | undefined;
113
- }, ListResult<SignInRow>>;
114
- readonly profileSessions: import("../../client").ApiRoute<void, SessionList>;
113
+ }, ListResult<SignInRow>, unknown>;
114
+ readonly profileSessions: import("../../client").ApiRoute<void, SessionList, unknown>;
115
115
  readonly profileRevokeSession: import("../../client").ApiRoute<{
116
116
  session_id: number;
117
- }, void>;
117
+ }, void, unknown>;
118
118
  };
@@ -3,48 +3,48 @@ export declare const notificationRoutes: {
3
3
  readonly list: import("../../client").ApiRoute<{
4
4
  before_id?: number | undefined;
5
5
  limit?: number | undefined;
6
- }, Page>;
7
- readonly unread: import("../../client").ApiRoute<void, UnreadCount>;
6
+ }, Page, unknown>;
7
+ readonly unread: import("../../client").ApiRoute<void, UnreadCount, unknown>;
8
8
  readonly read: import("../../client").ApiRoute<{
9
9
  id: number;
10
- }, UnreadCount>;
10
+ }, UnreadCount, unknown>;
11
11
  readonly readAll: import("../../client").ApiRoute<{
12
12
  up_to_id: number;
13
- }, UnreadCount>;
13
+ }, UnreadCount, unknown>;
14
14
  readonly stream: import("../../client").RawRoute;
15
- readonly test: import("../../client").ApiRoute<void, void>;
16
- readonly preferences: import("../../client").ApiRoute<void, Preferences>;
15
+ readonly test: import("../../client").ApiRoute<void, void, unknown>;
16
+ readonly preferences: import("../../client").ApiRoute<void, Preferences, unknown>;
17
17
  readonly preferencesSetEmail: import("../../client").ApiRoute<{
18
18
  category: string;
19
19
  email: boolean | null;
20
- }, CategorySettings>;
20
+ }, CategorySettings, unknown>;
21
21
  readonly quietHours: import("../../client").ApiRoute<{
22
22
  enabled: boolean;
23
23
  start: number;
24
24
  end: number;
25
- }, QuietHours>;
25
+ }, QuietHours, unknown>;
26
26
  readonly preferencesSetPush: import("../../client").ApiRoute<{
27
27
  category: string;
28
28
  push: boolean | null;
29
- }, CategorySettings>;
30
- readonly push: import("../../client").ApiRoute<void, PushConfig>;
31
- readonly devices: import("../../client").ApiRoute<void, DeviceList>;
29
+ }, CategorySettings, unknown>;
30
+ readonly push: import("../../client").ApiRoute<void, PushConfig, unknown>;
31
+ readonly devices: import("../../client").ApiRoute<void, DeviceList, unknown>;
32
32
  readonly deviceSubscribe: import("../../client").ApiRoute<{
33
33
  endpoint: string;
34
34
  p256dh: string;
35
35
  auth: string;
36
- }, Device>;
36
+ }, Device, unknown>;
37
37
  readonly deviceUnsubscribe: import("../../client").ApiRoute<{
38
38
  endpoint: string;
39
- }, DeviceList>;
39
+ }, DeviceList, unknown>;
40
40
  readonly deviceRename: import("../../client").ApiRoute<{
41
41
  id: number;
42
42
  label: string;
43
- }, Device>;
43
+ }, Device, unknown>;
44
44
  readonly deviceRemove: import("../../client").ApiRoute<{
45
45
  id: number;
46
- }, DeviceList>;
46
+ }, DeviceList, unknown>;
47
47
  readonly deviceTest: import("../../client").ApiRoute<{
48
48
  id: number;
49
- }, DeviceList>;
49
+ }, DeviceList, unknown>;
50
50
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wssto2/vue-core",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "goCore": "v1.8.0",
5
5
  "description": "Shared Vue 3 library for go-core applications: app shell, list / record / form pages and their controls.",
6
6
  "keywords": [