@protobase/client 0.19.16 → 0.21.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/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FilterInput, ListParams, MapParams } from "./query-string.js";
2
2
  import { ClientOptions } from "./transport.js";
3
3
  import { UploadProgress } from "./upload-request.js";
4
- import { BatchOp, BatchResult, Facet, Histogram, ListPage, MapResult, MetaResult, RecordOf, ResourceRef, Series, SeriesParams, Stored } from "./types.js";
4
+ import { Aggregate, AggregateParams, BatchOp, BatchResult, Facet, Histogram, HistoryPage, ListPage, MapResult, MetaResult, RecordOf, ResourceRef, Series, SeriesParams, Stored } from "./types.js";
5
5
  import { KeyValue } from "@protobase/schema";
6
6
  //#region src/client.d.ts
7
7
  /** How `invoke` calls a function: GET without a body, POST with one, unless `method` says otherwise. */
@@ -53,12 +53,17 @@ export declare const createClient: (options?: ClientOptions) => {
53
53
  }) => Promise<void>;
54
54
  undelete: <R extends ResourceRef>(resource: R, key: KeyValue | readonly KeyValue[]) => Promise<Stored<RecordOf<R>>>;
55
55
  reveal: (resource: ResourceRef, key: KeyValue | readonly KeyValue[], field: string) => Promise<unknown>;
56
+ history: (resource: ResourceRef, key: KeyValue | readonly KeyValue[], { pageSize, pageToken }?: {
57
+ pageSize?: number;
58
+ pageToken?: string;
59
+ }) => Promise<HistoryPage>;
56
60
  batchWrite: (ops: BatchOp[]) => Promise<BatchResult>;
57
61
  facets: (resource: ResourceRef, field: string, o?: {
58
62
  filter?: FilterInput;
59
63
  limit?: number;
60
64
  label?: string;
61
65
  }) => Promise<Facet[]>;
66
+ aggregate: (resource: ResourceRef, params: AggregateParams) => Promise<Aggregate>;
62
67
  series: (resource: ResourceRef, params: SeriesParams & {
63
68
  filter?: FilterInput;
64
69
  }) => Promise<Series>;
package/dist/client.js CHANGED
@@ -123,6 +123,25 @@ const createClient = (options = {}) => {
123
123
  body: { field }
124
124
  })).json()).value;
125
125
  };
126
+ /** A page of a record's changes, newest first, for a resource with `.history()`; `pageToken` is the previous page's `nextPageToken`. */
127
+ const history = async (resource, key, { pageSize, pageToken } = {}) => {
128
+ const query = queryString({
129
+ page_size: pageSize,
130
+ page_token: pageToken || void 0
131
+ });
132
+ const body = await (await send({
133
+ method: "GET",
134
+ path: `${keyPath(resource, key)}:history`,
135
+ query
136
+ })).json();
137
+ return {
138
+ items: body.items.map(({ database_role, ...change }) => ({
139
+ ...change,
140
+ databaseRole: database_role
141
+ })),
142
+ nextPageToken: body.next_page_token
143
+ };
144
+ };
126
145
  /** Applies several writes atomically (`POST /api/v1:batchWrite`), for example a record and its lines on Save. */
127
146
  const batchWrite = async (ops) => {
128
147
  const keyText = (key) => typeof key === "object" && key !== null && "$ref" in key ? key : encodeKey(key);
@@ -152,6 +171,32 @@ const createClient = (options = {}) => {
152
171
  })
153
172
  })).json()).facets;
154
173
  };
174
+ /** Totals per value of a field, or per bucket of a date field (`:aggregate`). */
175
+ const aggregate = async (resource, params) => {
176
+ const body = await (await send({
177
+ method: "GET",
178
+ path: `/${nameOf(resource)}:aggregate`,
179
+ query: queryString({
180
+ group_by: params.groupBy,
181
+ filter: filterText(params.filter) || void 0,
182
+ sum: params.sum,
183
+ average: params.average,
184
+ limit: params.limit,
185
+ label: params.label,
186
+ granularity: params.granularity,
187
+ range: params.range,
188
+ from: params.from,
189
+ to: params.to,
190
+ time_zone: params.timeZone
191
+ })
192
+ })).json();
193
+ return {
194
+ groupBy: body.group_by,
195
+ granularity: body.granularity,
196
+ timeZone: body.time_zone,
197
+ groups: body.groups
198
+ };
199
+ };
155
200
  const series = async (resource, params) => {
156
201
  const body = await (await send({
157
202
  method: "GET",
@@ -287,8 +332,10 @@ const createClient = (options = {}) => {
287
332
  remove,
288
333
  undelete,
289
334
  reveal,
335
+ history,
290
336
  batchWrite,
291
337
  facets,
338
+ aggregate,
292
339
  series,
293
340
  histogram,
294
341
  map,
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FilterInput, ListParams, MapParams, filterText, listWire } from "./query-string.js";
2
2
  import { ClientOptions } from "./transport.js";
3
3
  import { UploadProgress } from "./upload-request.js";
4
- import { BatchOp, BatchRef, BatchResult, Facet, Histogram, HistogramBucket, ListPage, MapBounds, MapBucket, MapLayerModel, MapResult, Meta, MetaResult, PluginRef, RecordOf, RecordPermissions, RecordPhotos, RelatedLabels, ResourcePermissions, ResourceRef, Series, SeriesParams, SeriesPoint, SourceRef, Stored, StoredFile, StoredFileVariant } from "./types.js";
4
+ import { Aggregate, AggregateGroup, AggregateParams, BatchOp, BatchRef, BatchResult, Facet, Histogram, HistogramBucket, HistoryChange, HistoryPage, ListPage, MapBounds, MapBucket, MapLayerModel, MapResult, Meta, MetaResult, PluginRef, RecordOf, RecordPermissions, RecordPhotos, RelatedLabels, ResourcePermissions, ResourceRef, Series, SeriesParams, SeriesPoint, SourceRef, Stored, StoredFile, StoredFileVariant } from "./types.js";
5
5
  import { Client, InvokeOptions, UploadOptions, UploadResult, createClient } from "./client.js";
6
6
  import { ApiError, PreconditionFailedError, ProblemDetails, ProblemError, isApiError } from "./problem.js";
7
7
  import { fileUrl } from "./file-urls.js";
@@ -18,4 +18,4 @@ import { AuthSession, AuthSessionOptions, createAuthSession, tokenExpiry } from
18
18
  import { createStaticSession } from "./static-session.js";
19
19
  import { AssistantClient, AssistantClientOptions, AssistantConnection, createAssistantClient } from "./assistant.js";
20
20
  import { RuntimeClient, RuntimeClientOptions, RuntimeLastUpdate, RuntimePolicy, RuntimeStatus, RuntimeUpdateStage, createRuntimeClient } from "./runtime.js";
21
- export { type AccountSecurity, type AccountSignIn, type ActiveRole, ApiError, type AssistantClient, type AssistantClientOptions, type AssistantConnection, AuthError, type AuthSession, type AuthSessionOptions, type AuthUser, type AuthenticatorSetup, type BatchOp, type BatchRef, type BatchResult, type Client, type ClientOptions, type CurrentOrganization, type Facet, type FilterInput, type Histogram, type HistogramBucket, type InvitationPreview, type InvitationSent, type InvokeOptions, type ListPage, type ListParams, type MapBounds, type MapBucket, type MapLayerModel, type MapParams, type MapResult, type Meta, type MetaResult, type Organization, type OrganizationInvitation, type OrganizationMember, type OrganizationRole, type OrganizationsClient, type Passkey, type PlatformSignIn, type PluginRef, PreconditionFailedError, type ProblemDetails, type ProblemError, type RecordOf, type RecordPermissions, type RecordPhotos, type RelatedLabels, type RequiredSetup, type ResourcePermissions, type ResourceRef, type RoleLabel, type RoleOption, type RolesClient, type RuntimeClient, type RuntimeClientOptions, type RuntimeLastUpdate, type RuntimePolicy, type RuntimeStatus, type RuntimeUpdateStage, type Series, type SeriesParams, type SeriesPoint, type SetupStatus, type SignInMethod, type SignInPolicy, type SignInPolicyClient, type SignInPolicyState, type SignInResult, type SignInRule, type SourceMeta, type SourceRef, type StaffAccessRule, type StaffSignIn, type StaffSignInClient, type Stored, type StoredFile, type StoredFileVariant, type TwoFactorMethod, type UploadOptions, type UploadProgress, type UploadResult, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, fileUrl, filterText, isApiError, listWire, routedClient, sourceMeta, tokenExpiry };
21
+ export { type AccountSecurity, type AccountSignIn, type ActiveRole, type Aggregate, type AggregateGroup, type AggregateParams, ApiError, type AssistantClient, type AssistantClientOptions, type AssistantConnection, AuthError, type AuthSession, type AuthSessionOptions, type AuthUser, type AuthenticatorSetup, type BatchOp, type BatchRef, type BatchResult, type Client, type ClientOptions, type CurrentOrganization, type Facet, type FilterInput, type Histogram, type HistogramBucket, type HistoryChange, type HistoryPage, type InvitationPreview, type InvitationSent, type InvokeOptions, type ListPage, type ListParams, type MapBounds, type MapBucket, type MapLayerModel, type MapParams, type MapResult, type Meta, type MetaResult, type Organization, type OrganizationInvitation, type OrganizationMember, type OrganizationRole, type OrganizationsClient, type Passkey, type PlatformSignIn, type PluginRef, PreconditionFailedError, type ProblemDetails, type ProblemError, type RecordOf, type RecordPermissions, type RecordPhotos, type RelatedLabels, type RequiredSetup, type ResourcePermissions, type ResourceRef, type RoleLabel, type RoleOption, type RolesClient, type RuntimeClient, type RuntimeClientOptions, type RuntimeLastUpdate, type RuntimePolicy, type RuntimeStatus, type RuntimeUpdateStage, type Series, type SeriesParams, type SeriesPoint, type SetupStatus, type SignInMethod, type SignInPolicy, type SignInPolicyClient, type SignInPolicyState, type SignInResult, type SignInRule, type SourceMeta, type SourceRef, type StaffAccessRule, type StaffSignIn, type StaffSignInClient, type Stored, type StoredFile, type StoredFileVariant, type TwoFactorMethod, type UploadOptions, type UploadProgress, type UploadResult, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, fileUrl, filterText, isApiError, listWire, routedClient, sourceMeta, tokenExpiry };
@@ -17,12 +17,14 @@ const routedClient = (own, sourceOf) => {
17
17
  remove: (resource, key, options) => to(resource).remove(resource, key, options),
18
18
  undelete: (resource, key) => to(resource).undelete(resource, key),
19
19
  reveal: (resource, key, field) => to(resource).reveal(resource, key, field),
20
+ history: (resource, key, options) => to(resource).history(resource, key, options),
20
21
  batchWrite: (ops) => {
21
22
  const apis = [...new Set(ops.map((op) => to(op.resource)))];
22
23
  if (apis.length > 1) return Promise.reject(/* @__PURE__ */ new Error(`A batch writes to one API, but these writes are for ${[...new Set(ops.map((op) => nameOf(op.resource)))].join(", ")}, which different APIs serve`));
23
24
  return (apis[0] ?? own).batchWrite(ops);
24
25
  },
25
26
  facets: (resource, field, options) => to(resource).facets(resource, field, options),
27
+ aggregate: (resource, params) => to(resource).aggregate(resource, params),
26
28
  series: (resource, params) => to(resource).series(resource, params),
27
29
  histogram: (resource, field, options) => to(resource).histogram(resource, field, options),
28
30
  map: (resource, params) => to(resource).map(resource, params),
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { FilterInput } from "./query-string.js";
1
2
  import { BottomBarModel, InferRecord, ResourceModel, SignInViewModel, UserMenuModel, ViewModel } from "@protobase/schema";
2
3
  import { PageModel } from "@protobase/layout";
3
4
  //#region src/types.d.ts
@@ -14,6 +15,31 @@ export type RecordOf<R extends ResourceRef> = R extends {
14
15
  export type RelatedLabels = Record<string, Record<string, string>>;
15
16
  /** Per record, by key as text, the files of its first photos in their order; a record without any is absent. */
16
17
  export type RecordPhotos = Record<string, StoredFile[]>;
18
+ /** One change of a record, as `history` reads it: only the fields the caller may read. */
19
+ export type HistoryChange = {
20
+ id: string;
21
+ /** When its transaction started, ISO 8601. */
22
+ at: string;
23
+ operation: 'create' | 'update' | 'delete' | 'undelete';
24
+ /** The fields an update changed, sensitive ones included; none for a create or delete. */
25
+ changed: string[];
26
+ /** The fields before and after, without sensitive and file fields; none before a create, or after a delete. */
27
+ before?: Record<string, unknown>;
28
+ after?: Record<string, unknown>;
29
+ /** Who made it through the API, with their name when the server knows it; `null` for a write from elsewhere. */
30
+ actor: {
31
+ id: string;
32
+ name?: string;
33
+ } | null;
34
+ /** The database role that wrote; `null` when unknown. */
35
+ databaseRole: string | null;
36
+ };
37
+ /** A page of a record's history, newest first. */
38
+ export type HistoryPage = {
39
+ items: HistoryChange[];
40
+ /** `""` on the last page. */
41
+ nextPageToken: string;
42
+ };
17
43
  export type ListPage<T> = {
18
44
  items: T[];
19
45
  /** `""` on the last page. */
@@ -54,6 +80,39 @@ export type SeriesParams = {
54
80
  granularity?: 'hour' | 'day' | 'week' | 'month';
55
81
  timeZone?: string;
56
82
  };
83
+ export type AggregateParams = {
84
+ /** A filterable field: its values make the groups, or for a date or timestamp field its buckets. */
85
+ groupBy: string;
86
+ filter?: FilterInput;
87
+ /** A numeric field to add up per group. */
88
+ sum?: string;
89
+ /** A numeric field to average per group, instead of `sum`. */
90
+ average?: string;
91
+ /** Value groups only: the most to return, default 100. */
92
+ limit?: number;
93
+ /** Value groups only: for a relation, the field of the related record that names each group. */
94
+ label?: string;
95
+ /** Date groups only. */
96
+ granularity?: 'hour' | 'day' | 'week' | 'month' | 'year';
97
+ range?: '7d' | '30d' | '90d' | '1y' | 'all';
98
+ from?: string;
99
+ to?: string;
100
+ timeZone?: string;
101
+ };
102
+ /** One group: its value (a date group's bucket in local ISO time), how many records it holds and its sum or average. */
103
+ export type AggregateGroup = {
104
+ value: string | number | boolean | null;
105
+ label?: string;
106
+ count: number;
107
+ sum?: number | null;
108
+ average?: number | null;
109
+ };
110
+ export type Aggregate = {
111
+ groupBy: string;
112
+ granularity?: string;
113
+ timeZone?: string;
114
+ groups: AggregateGroup[];
115
+ };
57
116
  export type HistogramBucket = {
58
117
  from: number;
59
118
  to: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/client",
3
- "version": "0.19.16",
3
+ "version": "0.21.0",
4
4
  "description": "Typed fetch client for the Protobase REST API.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -30,8 +30,8 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@better-auth/passkey": "^1.7.7",
33
- "@protobase/layout": "0.19.16",
34
- "@protobase/schema": "0.19.16",
33
+ "@protobase/layout": "0.21.0",
34
+ "@protobase/schema": "0.21.0",
35
35
  "@simplewebauthn/browser": "^13.3.0",
36
36
  "better-auth": "^1.7.7"
37
37
  }