@protobase/server 0.53.8 → 0.54.1

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.
@@ -2,6 +2,7 @@ import { UserColumn } from "./user-table.js";
2
2
  import { Mailer } from "../mail/smtp-mailer.js";
3
3
  import { SignInPolicy } from "./sign-in-policy.js";
4
4
  import { StaffSignIn } from "./staff-log.js";
5
+ import { Person } from "./organizations/people-endpoint.js";
5
6
  import { RoleDefinitions } from "./organizations/role-definitions.js";
6
7
  import { ConnectedApp } from "./mcp/connected-apps.js";
7
8
  import { ReplacingContext } from "./end-replaced-session.js";
@@ -5222,6 +5223,34 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
5222
5223
  }> | {
5223
5224
  id: "protobase-organizations";
5224
5225
  endpoints: {
5226
+ peopleEndpoint: import("better-call").StrictEndpoint<"/organization/people", {
5227
+ method: "GET";
5228
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
5229
+ session: {
5230
+ session: Record<string, any> & {
5231
+ id: string;
5232
+ createdAt: Date;
5233
+ updatedAt: Date;
5234
+ userId: string;
5235
+ expiresAt: Date;
5236
+ token: string;
5237
+ ipAddress?: string | null | undefined;
5238
+ userAgent?: string | null | undefined;
5239
+ };
5240
+ user: Record<string, any> & {
5241
+ id: string;
5242
+ createdAt: Date;
5243
+ updatedAt: Date;
5244
+ email: string;
5245
+ emailVerified: boolean;
5246
+ name: string;
5247
+ image?: string | null | undefined;
5248
+ };
5249
+ };
5250
+ }>>[];
5251
+ }, {
5252
+ people: Person[];
5253
+ }>;
5225
5254
  setAppRoles: import("better-call").StrictEndpoint<"/organization/set-app-roles", {
5226
5255
  method: "POST";
5227
5256
  use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
@@ -2,6 +2,7 @@ import { UserColumn, UserTableOptions } from "./user-table.js";
2
2
  import { Mailer } from "../mail/smtp-mailer.js";
3
3
  import { SignInPolicy } from "./sign-in-policy.js";
4
4
  import { StaffSignIn } from "./staff-log.js";
5
+ import { Person } from "./organizations/people-endpoint.js";
5
6
  import { RoleDefinitions, RolesInput } from "./organizations/role-definitions.js";
6
7
  import { ConnectedApp } from "./mcp/connected-apps.js";
7
8
  import { ReplacingContext } from "./end-replaced-session.js";
@@ -5341,6 +5342,34 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
5341
5342
  }> | {
5342
5343
  id: "protobase-organizations";
5343
5344
  endpoints: {
5345
+ peopleEndpoint: import("better-call").StrictEndpoint<"/organization/people", {
5346
+ method: "GET";
5347
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
5348
+ session: {
5349
+ session: Record<string, any> & {
5350
+ id: string;
5351
+ createdAt: Date;
5352
+ updatedAt: Date;
5353
+ userId: string;
5354
+ expiresAt: Date;
5355
+ token: string;
5356
+ ipAddress?: string | null | undefined;
5357
+ userAgent?: string | null | undefined;
5358
+ };
5359
+ user: Record<string, any> & {
5360
+ id: string;
5361
+ createdAt: Date;
5362
+ updatedAt: Date;
5363
+ email: string;
5364
+ emailVerified: boolean;
5365
+ name: string;
5366
+ image?: string | null | undefined;
5367
+ };
5368
+ };
5369
+ }>>[];
5370
+ }, {
5371
+ people: Person[];
5372
+ }>;
5344
5373
  setAppRoles: import("better-call").StrictEndpoint<"/organization/set-app-roles", {
5345
5374
  method: "POST";
5346
5375
  use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
@@ -0,0 +1,8 @@
1
+ //#region src/better-auth/organizations/people-endpoint.d.ts
2
+ /** A member as everyone in the organization may see them: their user id, name and photo, never their address. */
3
+ export type Person = {
4
+ id: string;
5
+ name: string;
6
+ image?: string;
7
+ };
8
+ //#endregion
@@ -0,0 +1,48 @@
1
+ import { everyRow, findMember, membersOf } from "./store.js";
2
+ import { APIError, createAuthEndpoint, sessionMiddleware } from "better-auth/api";
3
+ //#region src/better-auth/organizations/people-endpoint.ts
4
+ /** The people of these users, by name; one without a name is shown by nothing else, so is left out. */
5
+ const peopleOf = (users) => users.flatMap((user) => user.name ? [{
6
+ id: user.id,
7
+ name: user.name,
8
+ ...user.image && { image: user.image }
9
+ }] : []).sort((a, b) => a.name.localeCompare(b.name));
10
+ /**
11
+ * `GET /organization/people`: the members of the organization the session works in, for every member of it, as
12
+ * `{ people: Person[] }`, to show authors and offer mentions. The organization comes from the session alone, never
13
+ * from the request, and someone who is not a member of it, a global role included, is refused.
14
+ */
15
+ const peopleEndpoint = createAuthEndpoint("/organization/people", {
16
+ method: "GET",
17
+ use: [sessionMiddleware]
18
+ }, async (ctx) => {
19
+ const { adapter } = ctx.context;
20
+ const { user, session } = ctx.context.session;
21
+ const organizationId = session.activeOrganizationId;
22
+ const member = organizationId ? await findMember(adapter, {
23
+ organizationId,
24
+ userId: user.id
25
+ }) : void 0;
26
+ if (!organizationId || !member) throw new APIError("FORBIDDEN", {
27
+ code: "NOT_A_MEMBER",
28
+ message: "Only the members of the organization you work in can see its people."
29
+ });
30
+ const ids = (await membersOf(adapter, organizationId)).map((row) => row.userId);
31
+ const users = await adapter.findMany({
32
+ model: "user",
33
+ where: [{
34
+ field: "id",
35
+ operator: "in",
36
+ value: ids
37
+ }],
38
+ select: [
39
+ "id",
40
+ "name",
41
+ "image"
42
+ ],
43
+ limit: everyRow
44
+ });
45
+ return ctx.json({ people: peopleOf(users) });
46
+ });
47
+ //#endregion
48
+ export { peopleEndpoint, peopleOf };
@@ -1,17 +1,19 @@
1
1
  import { invitationLinkHook } from "../invitations/invitation-link-hook.js";
2
2
  import { invitationEndpoints } from "./invitation-endpoints.js";
3
3
  import { memberEndpoints } from "./member-endpoints.js";
4
+ import { peopleEndpoint } from "./people-endpoint.js";
4
5
  //#region src/better-auth/organizations/protobase-plugin.ts
5
6
  /**
6
7
  * Protobase's endpoints beside Better Auth's organization plugin: accepting invitations signed in, app roles, handing
7
- * ownership over, and finding organizations for people with a global role. Without a mailer, whoever invites gets the
8
- * link in the answer.
8
+ * ownership over, the people of the organization one works in for its members, and finding organizations for people
9
+ * with a global role. Without a mailer, whoever invites gets the link in the answer.
9
10
  */
10
11
  const protobaseOrganizationPlugin = ({ resolved, mail }) => ({
11
12
  id: "protobase-organizations",
12
13
  endpoints: {
13
14
  ...invitationEndpoints({ resolved }),
14
- ...memberEndpoints({ resolved })
15
+ ...memberEndpoints({ resolved }),
16
+ peopleEndpoint
15
17
  },
16
18
  hooks: { after: mail ? [] : [invitationLinkHook(["/organization/invite-member"], resolved.invitationUrl)] }
17
19
  });
@@ -34,7 +34,7 @@ const sensitiveErrors = (view, model) => {
34
34
  ["the sidebar", layoutItems(view.layout).flatMap((item) => item.kind === "sidebar" ? item.fields : [])],
35
35
  ["a map", layoutItems(view.layout).flatMap((item) => item.kind === "map" ? [item.latitude, item.longitude] : [])],
36
36
  ["a gallery", layoutItems(view.layout).flatMap((item) => item.kind === "gallery" && item.image !== void 0 ? [item.image] : [])],
37
- ["the recent records", view.nav?.recent ? [view.nav.recent.status] : []],
37
+ ["the recent records", view.nav?.recent?.status === void 0 ? [] : [view.nav.recent.status]],
38
38
  ["an action", view.actions.flatMap((action) => [...actionFields(action.run), ...actionWhenFields(action.when)])]
39
39
  ].flatMap(([place, names]) => [...new Set(names.filter(sensitive))].map((name) => `sensitive field "${name}" cannot be in ${place}`));
40
40
  };
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.53.8";
2
+ var version = "0.54.1";
3
3
  //#endregion
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.53.8",
3
+ "version": "0.54.1",
4
4
  "description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -40,9 +40,9 @@
40
40
  "@better-auth/passkey": "^1.7.12",
41
41
  "@better-auth/sso": "^1.7.12",
42
42
  "@modelcontextprotocol/server": "^2.3.1",
43
- "@protobase/layout": "0.53.8",
44
- "@protobase/query": "0.53.8",
45
- "@protobase/schema": "0.53.8",
43
+ "@protobase/layout": "0.54.1",
44
+ "@protobase/query": "0.54.1",
45
+ "@protobase/schema": "0.54.1",
46
46
  "@react-email/render": "^2.1.0",
47
47
  "@scalar/hono-api-reference": "^0.12.10",
48
48
  "@sentry/core": "^11.7.0",