@protobase/server 0.11.0 → 0.11.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.
@@ -1,4 +1,5 @@
1
1
  import { AuditQueue, PipelineHook, ScanGuardMode } from "./types.js";
2
+ import { PluginOption } from "./plugins/plugin-settings.js";
2
3
  import { CorsOrigins } from "./api-cors.js";
3
4
  import { AssistantOptions } from "./assistant/assistant-settings.js";
4
5
  import { RuntimeOptions } from "./runtime/runtime-settings.js";
@@ -39,5 +40,10 @@ export type AdminOptions = {
39
40
  cors?: CorsOrigins;
40
41
  /** The runtime updates endpoint behind the top bar's update button (see `RuntimeOptions`); `false` turns it off. */
41
42
  runtime?: RuntimeOptions | false;
43
+ /**
44
+ * The plugins the admin app loads (see `PluginOption`), before the ones the platform lists in `PROTOBASE_PLUGINS`;
45
+ * `false` turns both off.
46
+ */
47
+ plugins?: PluginOption[] | false;
42
48
  };
43
49
  //#endregion
@@ -19,6 +19,7 @@ import { checkViews } from "./check-views.js";
19
19
  import { createFilesRuntime } from "./files/runtime.js";
20
20
  import { fileRoutes } from "./files/routes.js";
21
21
  import { functionRoutes } from "./functions/routes.js";
22
+ import { pluginOptions } from "./plugins/plugin-settings.js";
22
23
  import { runtimeUrl } from "./runtime/runtime-settings.js";
23
24
  import { createMeta } from "./meta.js";
24
25
  import { buildRegistry } from "./registry.js";
@@ -58,6 +59,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
58
59
  const systemPath = basePath.slice(0, basePath.lastIndexOf("/"));
59
60
  const assistant = assistantSettings(options.assistant, globalThis.process?.env ?? {});
60
61
  const runtime = runtimeUrl(options.runtime, globalThis.process?.env ?? {});
62
+ const plugins = pluginOptions(options.plugins, globalThis.process?.env ?? {});
61
63
  const files = createFilesRuntime({
62
64
  ...filesOptions && { options: filesOptions },
63
65
  env: globalThis.process?.env ?? {},
@@ -85,6 +87,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
85
87
  rowPermissions: (resource) => typeof options.rowPermissions === "object" ? !options.rowPermissions.except.includes(resource) : options.rowPermissions !== false,
86
88
  ...assistant && { assistant: assistant.kind === "external" ? assistant.url : `${systemPath}/assistant` },
87
89
  ...runtime && { runtime },
90
+ plugins,
88
91
  ...files && { files },
89
92
  ...registry.entries.some((entry) => entry.model.events) && { actorSetting: `${changesSchema(events)}.actor` }
90
93
  };
package/dist/deps.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import "./types.js";
2
2
  import "./files/runtime.js";
3
+ import "./plugins/plugin-settings.js";
3
4
  import "./registry.js";
4
5
  import "./scan-guard.js";
5
6
  import { PageModel } from "@protobase/layout";
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ import { FileProvider, FileStore, StoredObject } from "./files/store.js";
16
16
  import { FilesOptions } from "./files/options.js";
17
17
  import { CleanupEntry, CleanupSchedule, ScheduledDelete, storageCleanupSchedule } from "./files/cleanup-schedule.js";
18
18
  import { CleanupReport } from "./files/cleanup-runner.js";
19
+ import { PluginOption, PluginRef, pluginOptions, pluginsFor, pluginsVariable } from "./plugins/plugin-settings.js";
19
20
  import { ResourceSource, configExports } from "./resource-source.js";
20
21
  import { RecordKeyInput, ToolRecord, ToolRecords } from "./assistant/records.js";
21
22
  import { FunctionRecords, ListParams, RecordPage } from "./functions/records.js";
@@ -68,4 +69,4 @@ import { FatalJobError } from "./jobs/run-job.js";
68
69
  import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/runtime.js";
69
70
  import { jobsDrainApp } from "./jobs/drain-route.js";
70
71
  import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
71
- export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticatorOptions, type CapturedRow, type ChatMessage, type ChatTextPart, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DrainResult, type EnqueueOptions, type EventData, type EventsOptions, FatalJobError, type FileCleanupInput, type FileObject, type FileProvider, type FileStore, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSource, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type LinkedAccount, type ListParams, type LocalFilesOptions, type MemberInput, ModelError, type ModelSettings, type NewOrganization, type NewUser, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PipelineHook, type PlatformSignIn, type ProjectConfig, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RecordKeyInput, type RecordPage, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type SignInPolicy, type SignInRule, type SignatureOptions, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoredMember, type StoredObject, type StoredOrganization, type StoredUser, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TurnOptions, type User, type UserCreatedHook, type ViewSource, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineFunction, defineJob, defineTool, deleteUser, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, functionApp, hasUsers, imageSize, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, listOrganizations, listUsers, localFileStore, localFiles, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, startJobs, storageCleanupSchedule, streamChatCompletion, subscription, unauthorized, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints };
72
+ export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticatorOptions, type CapturedRow, type ChatMessage, type ChatTextPart, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DrainResult, type EnqueueOptions, type EventData, type EventsOptions, FatalJobError, type FileCleanupInput, type FileObject, type FileProvider, type FileStore, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSource, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type LinkedAccount, type ListParams, type LocalFilesOptions, type MemberInput, ModelError, type ModelSettings, type NewOrganization, type NewUser, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type ProjectConfig, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RecordKeyInput, type RecordPage, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type SignInPolicy, type SignInRule, type SignatureOptions, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoredMember, type StoredObject, type StoredOrganization, type StoredUser, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TurnOptions, type User, type UserCreatedHook, type ViewSource, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineFunction, defineJob, defineTool, deleteUser, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, functionApp, hasUsers, imageSize, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, listOrganizations, listUsers, localFileStore, localFiles, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, startJobs, storageCleanupSchedule, streamChatCompletion, subscription, unauthorized, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ import { newWebhookSecret } from "./webhooks/standard-webhooks.js";
31
31
  import { subscription } from "./webhooks/subscription.js";
32
32
  import { storageCleanupSchedule } from "./files/cleanup-schedule.js";
33
33
  import { localFileStore, localFiles } from "./files/local-files.js";
34
+ import { pluginOptions, pluginsFor, pluginsVariable } from "./plugins/plugin-settings.js";
34
35
  import { runtimeUrl, runtimeVariable, seesRuntime } from "./runtime/runtime-settings.js";
35
36
  import { createAdmin } from "./create-admin.js";
36
37
  import { configExports } from "./resource-source.js";
@@ -51,4 +52,4 @@ import { createFileCleanup } from "./files/file-cleanup.js";
51
52
  import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/processors.js";
52
53
  import { startJobs } from "./jobs/runtime.js";
53
54
  import { jobsDrainApp } from "./jobs/drain-route.js";
54
- export { FatalJobError, HttpProblem, ModelError, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineFunction, defineJob, defineTool, deleteUser, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, functionApp, hasUsers, imageSize, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, listOrganizations, listUsers, localFileStore, localFiles, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, startJobs, storageCleanupSchedule, streamChatCompletion, subscription, unauthorized, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints };
55
+ export { FatalJobError, HttpProblem, ModelError, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineFunction, defineJob, defineTool, deleteUser, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, functionApp, hasUsers, imageSize, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, listOrganizations, listUsers, localFileStore, localFiles, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, startJobs, storageCleanupSchedule, streamChatCompletion, subscription, unauthorized, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints };
package/dist/meta.js CHANGED
@@ -2,6 +2,7 @@ import { seesAssistant } from "./assistant/assistant-settings.js";
2
2
  import { sha256Hex, stableJson } from "./hash.js";
3
3
  import { requestAccess } from "./request-access.js";
4
4
  import { activeRole } from "./active-role.js";
5
+ import { pluginsFor } from "./plugins/plugin-settings.js";
5
6
  import { seesRuntime } from "./runtime/runtime-settings.js";
6
7
  import { pruneView } from "./view-access.js";
7
8
  import { prunePage } from "@protobase/layout";
@@ -35,6 +36,7 @@ const createMeta = (deps) => {
35
36
  const shown = (item) => item.kind === "link" || (item.kind === "resource" ? visible.some((access) => access.entry.name === item.resource) : pages.some((page) => page.name === item.page));
36
37
  const bar = bottomBarFor(deps.bottomBars, activeRole(session));
37
38
  const barItems = bar?.items.filter(shown) ?? [];
39
+ const plugins = pluginsFor(deps.plugins, session.user.roles);
38
40
  const body = {
39
41
  resources: visible.map((access) => access.readable),
40
42
  views,
@@ -56,7 +58,8 @@ const createMeta = (deps) => {
56
58
  items: barItems
57
59
  } },
58
60
  ...deps.assistant && seesAssistant(session.user.roles) && { assistant: { url: deps.assistant } },
59
- ...deps.runtime && seesRuntime(session.user.roles) && { runtime: { url: deps.runtime } }
61
+ ...deps.runtime && seesRuntime(session.user.roles) && { runtime: { url: deps.runtime } },
62
+ ...plugins.length > 0 && { plugins }
60
63
  };
61
64
  return {
62
65
  body,
@@ -0,0 +1,27 @@
1
+ import { JsonValue } from "@protobase/schema";
2
+ //#region src/plugins/plugin-settings.d.ts
3
+ /**
4
+ * A plugin the admin app loads at runtime: `url` names its plugin.json (`protobase build-plugin` writes it), on another
5
+ * origin or this one (`/plugins/...`). The plugin reads `settings` with `usePlugin()`. With `roles`, `/meta` names it
6
+ * only to callers holding one of them; without, to everyone.
7
+ */
8
+ export type PluginOption = {
9
+ url: string;
10
+ settings?: Record<string, JsonValue>;
11
+ roles?: string[];
12
+ };
13
+ /** A plugin as `/meta` names it to a caller. */
14
+ export type PluginRef = {
15
+ url: string;
16
+ settings?: Record<string, JsonValue>;
17
+ };
18
+ /** The platform's plugins, as plugin.json URLs separated by commas, loaded after the ones `options.plugins` lists. */
19
+ export declare const pluginsVariable = "PROTOBASE_PLUGINS";
20
+ /**
21
+ * The plugins the app loads: those `options.plugins` lists, then those `PROTOBASE_PLUGINS` adds, each URL once. `false`
22
+ * turns both off. A value that is no URL stops the server at startup.
23
+ */
24
+ export declare const pluginOptions: (option: PluginOption[] | false | undefined, env: Record<string, string | undefined>) => PluginOption[];
25
+ /** The plugins `/meta` names to a caller with `roles`: those for everyone, and those for one of their roles. */
26
+ export declare const pluginsFor: (plugins: readonly PluginOption[], roles: readonly string[]) => PluginRef[];
27
+ //#endregion
@@ -0,0 +1,31 @@
1
+ //#region src/plugins/plugin-settings.ts
2
+ /** The platform's plugins, as plugin.json URLs separated by commas, loaded after the ones `options.plugins` lists. */
3
+ const pluginsVariable = "PROTOBASE_PLUGINS";
4
+ const checkedPluginUrl = (url, source) => {
5
+ if (url.startsWith("/") && !url.startsWith("//")) return url;
6
+ if (!URL.canParse(url)) throw new Error(`${source} names "${url}", which is no URL; use https://... or a path such as /plugins/name/plugin.json`);
7
+ const { protocol } = new URL(url);
8
+ if (protocol !== "https:" && protocol !== "http:") throw new Error(`${source} names "${url}", which must start with https:// or http://, not ${protocol}//`);
9
+ return url;
10
+ };
11
+ /**
12
+ * The plugins the app loads: those `options.plugins` lists, then those `PROTOBASE_PLUGINS` adds, each URL once. `false`
13
+ * turns both off. A value that is no URL stops the server at startup.
14
+ */
15
+ const pluginOptions = (option, env) => {
16
+ if (option === false) return [];
17
+ const given = (option ?? []).map((plugin) => ({
18
+ ...plugin,
19
+ url: checkedPluginUrl(plugin.url.trim(), "options.plugins")
20
+ }));
21
+ const listed = (env["PROTOBASE_PLUGINS"] ?? "").split(",").map((url) => url.trim()).filter((url) => url !== "").map((url) => ({ url: checkedPluginUrl(url, pluginsVariable) }));
22
+ const all = [...given, ...listed];
23
+ return all.filter((plugin, index) => all.findIndex((other) => other.url === plugin.url) === index);
24
+ };
25
+ /** The plugins `/meta` names to a caller with `roles`: those for everyone, and those for one of their roles. */
26
+ const pluginsFor = (plugins, roles) => plugins.filter((plugin) => !plugin.roles || plugin.roles.some((role) => roles.includes(role))).map(({ url, settings }) => ({
27
+ url,
28
+ ...settings && { settings }
29
+ }));
30
+ //#endregion
31
+ export { pluginOptions, pluginsFor, pluginsVariable };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.11.0",
3
+ "version": "0.11.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": {
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@better-auth/passkey": "^1.7.7",
33
- "@protobase/layout": "0.11.0",
34
- "@protobase/query": "0.11.0",
35
- "@protobase/schema": "0.11.0",
33
+ "@protobase/layout": "0.11.1",
34
+ "@protobase/query": "0.11.1",
35
+ "@protobase/schema": "0.11.1",
36
36
  "@scalar/hono-api-reference": "^0.12.10",
37
37
  "@simplewebauthn/server": "^13.3.1",
38
38
  "better-auth": "^1.7.7",