@protobase/server 0.9.0 → 0.10.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/active-role.js +8 -0
- package/dist/admin-options.d.ts +8 -0
- package/dist/api-cors.d.ts +5 -0
- package/dist/api-cors.js +53 -0
- package/dist/better-auth/admin-only.js +5 -3
- package/dist/better-auth/authenticator.d.ts +1 -1
- package/dist/better-auth/authenticator.js +1 -1
- package/dist/better-auth/create-auth.d.ts +166 -160
- package/dist/better-auth/create-auth.js +40 -10
- package/dist/better-auth/operator-provider.d.ts +2 -1
- package/dist/better-auth/origins.d.ts +4 -0
- package/dist/better-auth/origins.js +43 -0
- package/dist/better-auth/passkey-domain.js +41 -0
- package/dist/better-auth/passkey-plugin.js +151 -0
- package/dist/better-auth/roles/active-role.js +26 -0
- package/dist/better-auth/roles/roles-plugin.js +73 -0
- package/dist/better-auth/roles/session-role.js +28 -0
- package/dist/better-auth/staff-sign-in-endpoints.js +9 -2
- package/dist/better-auth/status-route.js +5 -1
- package/dist/better-auth/tokens.d.ts +2 -1
- package/dist/better-auth/tokens.js +5 -2
- package/dist/check-shell.js +11 -2
- package/dist/create-admin.d.ts +5 -3
- package/dist/create-admin.js +23 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/jobs/failed-jobs.js +10 -10
- package/dist/jobs/functions-sql.js +8 -5
- package/dist/jobs/runtime.js +2 -0
- package/dist/meta.js +9 -2
- package/dist/openapi/components.js +1 -1
- package/dist/openapi/document.js +7 -5
- package/dist/openapi/naming.js +2 -1
- package/dist/resource-source.d.ts +3 -2
- package/dist/resource-source.js +3 -1
- package/dist/routes/docs.js +2 -2
- package/dist/webhooks/table/owner-roles.js +15 -9
- package/dist/webhooks/table/plugin.d.ts +1 -1
- package/dist/webhooks/table/plugin.js +1 -1
- package/dist/webhooks/table/validate-hook.js +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SignInPolicy, SignInRule, StaffAccessRule, defaultSignInPolicy, signInPolicyMethods } from "./better-auth/sign-in-policy.js";
|
|
2
2
|
import { StaffSignIn } from "./better-auth/staff-log.js";
|
|
3
|
-
import { RoleDefinition, RolesInput } from "./better-auth/organizations/role-definitions.js";
|
|
4
3
|
import { OperatorProvider, readOperatorSettings } from "./better-auth/operator-provider.js";
|
|
4
|
+
import { RoleDefinition, RolesInput } from "./better-auth/organizations/role-definitions.js";
|
|
5
5
|
import { OrganizationRole, StoredMember, StoredOrganization } from "./better-auth/organizations/store.js";
|
|
6
6
|
import { OrganizationsOptions } from "./better-auth/organizations/options.js";
|
|
7
7
|
import { PlatformSignIn, readPlatformSignIn } from "./better-auth/platform-sign-in.js";
|
|
@@ -20,6 +20,7 @@ import { ResourceSource, configExports } from "./resource-source.js";
|
|
|
20
20
|
import { RecordKeyInput, ToolRecord, ToolRecords } from "./assistant/records.js";
|
|
21
21
|
import { FunctionRecords, ListParams, RecordPage } from "./functions/records.js";
|
|
22
22
|
import { ApiFunction, CorsOptions, FunctionApp, FunctionCaller, FunctionContext, FunctionHandler, FunctionOptions, FunctionSource, ProtectedFunctionOptions, PublicFunctionContext, PublicFunctionHandler, PublicFunctionOptions, defineFunction } from "./functions/define-function.js";
|
|
23
|
+
import { CorsOrigins } from "./api-cors.js";
|
|
23
24
|
import { ChatMessage, ChatTextPart, Completion, CompletionOptions, ModelError, ModelSettings, ReasoningDetail, ReasoningEffort, ToolCall, ToolSpec, streamChatCompletion } from "./assistant/chat-completions.js";
|
|
24
25
|
import { ConversationRecord, ConversationStore } from "./assistant/conversation-store.js";
|
|
25
26
|
import { Conversation, ConversationsOptions, conversationKey, createConversations } from "./assistant/conversations.js";
|
|
@@ -37,6 +38,7 @@ import { BetterAuthAuthenticatorOptions, betterAuthAuthenticator } from "./bette
|
|
|
37
38
|
import { parseRoles } from "./better-auth/parse-roles.js";
|
|
38
39
|
import { LinkedAccount, NewUser, StoredUser, createUser, deleteUser, hasUsers, listUsers, roleChoices, setUserBanned, setUserRole } from "./better-auth/users.js";
|
|
39
40
|
import { IssueTokenOptions, issueToken, maxTokenTtlSeconds } from "./better-auth/tokens.js";
|
|
41
|
+
import { webauthnPath } from "./better-auth/origins.js";
|
|
40
42
|
import { authSchemaMigration, checkAuthSchema } from "./better-auth/auth-schema.js";
|
|
41
43
|
import { changesMigration, checkChanges, migrationCommand } from "./changes/capture-schema.js";
|
|
42
44
|
import { CapturedRow, CoalescedChange, coalesce } from "./changes/coalesce.js";
|
|
@@ -66,4 +68,4 @@ import { FatalJobError } from "./jobs/run-job.js";
|
|
|
66
68
|
import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/runtime.js";
|
|
67
69
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
68
70
|
import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
|
|
69
|
-
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 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, webhooks, webhooksMigration, widget, withCacheBreakpoints };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { ModelError, streamChatCompletion } from "./assistant/chat-completions.j
|
|
|
12
12
|
import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
|
|
13
13
|
import { runTurn } from "./assistant/turn.js";
|
|
14
14
|
import { consoleAuditQueue } from "./audit/console-queue.js";
|
|
15
|
+
import { webauthnPath } from "./better-auth/origins.js";
|
|
15
16
|
import { readOperatorSettings } from "./better-auth/operator-provider.js";
|
|
16
17
|
import { parseRoles } from "./better-auth/parse-roles.js";
|
|
17
18
|
import { defaultSignInPolicy, signInPolicyMethods } from "./better-auth/sign-in-policy.js";
|
|
@@ -50,4 +51,4 @@ import { createFileCleanup } from "./files/file-cleanup.js";
|
|
|
50
51
|
import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/processors.js";
|
|
51
52
|
import { startJobs } from "./jobs/runtime.js";
|
|
52
53
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
53
|
-
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, webhooks, webhooksMigration, widget, withCacheBreakpoints };
|
|
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 };
|
package/dist/jobs/failed-jobs.js
CHANGED
|
@@ -6,13 +6,13 @@ const admins = ({ user }) => user?.roles?.includes("admin") ?? false;
|
|
|
6
6
|
* The failed jobs, over the `jobs.failed` view: the admin app lists them with their last error, and retries or deletes
|
|
7
7
|
* one through the view's triggers. Admins only, whatever the project's roles say.
|
|
8
8
|
*/
|
|
9
|
-
const failedJobs = resource("
|
|
9
|
+
const failedJobs = resource("failed_jobs").table(`${jobsSchema}.failed`).fields({
|
|
10
10
|
id: f.uuid().readOnly().filterable(),
|
|
11
11
|
name: f.text().readOnly().filterable().sortable(),
|
|
12
12
|
error: f.text().optional().readOnly(),
|
|
13
13
|
attempts: f.integer().readOnly(),
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
failed_at: f.timestamp().readOnly().filterable().sortable(),
|
|
15
|
+
created_at: f.timestamp().readOnly().sortable(),
|
|
16
16
|
key: f.text().optional().readOnly().filterable(),
|
|
17
17
|
payload: f.json().optional().readOnly(),
|
|
18
18
|
output: f.json().optional().readOnly(),
|
|
@@ -24,23 +24,23 @@ const failedJobs = resource("failedJobs").table(`${jobsSchema}.failed`).fields({
|
|
|
24
24
|
delete: admins,
|
|
25
25
|
create: () => false
|
|
26
26
|
});
|
|
27
|
-
const failedJobsView = view("
|
|
27
|
+
const failedJobsView = view("failed_jobs").names({
|
|
28
28
|
singular: "Failed job",
|
|
29
29
|
plural: "Failed jobs"
|
|
30
30
|
}).icon("triangle-alert").title((r) => r.name).help("Jobs that used up their attempts, or failed for good. Retry one once its cause is fixed: it gets one more attempt.").fields((r) => ({
|
|
31
31
|
name: r.name.label("Job"),
|
|
32
32
|
error: r.error.label("Last error"),
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
failed_at: r.failed_at.label("Failed"),
|
|
34
|
+
created_at: r.created_at.label("Enqueued"),
|
|
35
35
|
output: r.output.label("Error details")
|
|
36
36
|
})).list((r) => ({
|
|
37
37
|
columns: [
|
|
38
38
|
r.name,
|
|
39
39
|
r.error,
|
|
40
40
|
r.attempts,
|
|
41
|
-
r.
|
|
41
|
+
r.failed_at
|
|
42
42
|
],
|
|
43
|
-
sort: [[r.
|
|
43
|
+
sort: [[r.failed_at, "desc"]]
|
|
44
44
|
})).layout((r) => [
|
|
45
45
|
l.section("Failure", [r.error, r.output]),
|
|
46
46
|
l.section("Job", [
|
|
@@ -50,8 +50,8 @@ const failedJobsView = view("failedJobs").names({
|
|
|
50
50
|
]),
|
|
51
51
|
l.sidebar([
|
|
52
52
|
r.attempts,
|
|
53
|
-
r.
|
|
54
|
-
r.
|
|
53
|
+
r.failed_at,
|
|
54
|
+
r.created_at
|
|
55
55
|
])
|
|
56
56
|
]).actions((a) => [a.update("retry", {
|
|
57
57
|
label: "Retry",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The comment each Protobase function in the jobs schema carries, which the startup check reads. */
|
|
2
|
-
const functionsComment = `Protobase jobs
|
|
2
|
+
const functionsComment = `Protobase jobs 3`;
|
|
3
3
|
/** Protobase's own functions beside pg-boss's tables, by name; each carries `functionsComment`. */
|
|
4
4
|
const functionNames = [
|
|
5
5
|
"enqueue",
|
|
@@ -11,7 +11,9 @@ const functionNames = [
|
|
|
11
11
|
* `jobs.enqueue(name, payload, run_at, key, group_key, priority)`: a job from SQL, such as a trigger, in the caller's
|
|
12
12
|
* transaction. It inserts what pg-boss's `send()` does, with the queue's retry settings; it creates a queue that no
|
|
13
13
|
* worker has created yet. A `key` keeps one waiting job, as `mode: 'dedupe'` does, and an ordered job takes its group
|
|
14
|
-
* as `group_key
|
|
14
|
+
* as `group_key`, and an id from `uuidv7()`, which rises within a database session: pg-boss runs a group's jobs by their
|
|
15
|
+
* transaction's start, then by id, so the jobs one transaction enqueues run in that order. Tied to the pg-boss schema
|
|
16
|
+
* version, which the startup check pins.
|
|
15
17
|
*/
|
|
16
18
|
const enqueue = (schema) => `create or replace function ${schema}.enqueue(
|
|
17
19
|
job_name text,
|
|
@@ -45,14 +47,15 @@ begin
|
|
|
45
47
|
end if;
|
|
46
48
|
execute format(
|
|
47
49
|
'insert into ${schema}.%I (name, data, priority, start_after, singleton_key, retry_limit, retry_delay, retry_backoff,
|
|
48
|
-
retry_delay_max, expire_seconds, deletion_seconds, keep_until, policy, dead_letter, heartbeat_seconds, upsert_by_key)
|
|
49
|
-
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $4 + $12 * interval ''1s'', $13, $14, $15, $16)
|
|
50
|
+
retry_delay_max, expire_seconds, deletion_seconds, keep_until, policy, dead_letter, heartbeat_seconds, upsert_by_key, id)
|
|
51
|
+
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $4 + $12 * interval ''1s'', $13, $14, $15, $16, $17)
|
|
50
52
|
on conflict do nothing
|
|
51
53
|
returning id',
|
|
52
54
|
queue.table_name)
|
|
53
55
|
using job_name, payload, priority, start, coalesce(key, group_key), queue.retry_limit, queue.retry_delay,
|
|
54
56
|
queue.retry_backoff, queue.retry_delay_max, queue.expire_seconds, queue.deletion_seconds, queue.retention_seconds,
|
|
55
|
-
queue.policy, queue.dead_letter, queue.heartbeat_seconds, key is not null
|
|
57
|
+
queue.policy, queue.dead_letter, queue.heartbeat_seconds, key is not null,
|
|
58
|
+
case when group_key is null then gen_random_uuid() else uuidv7() end
|
|
56
59
|
into job_id;
|
|
57
60
|
-- A concurrent enqueue of the same key inserted first: its job is the one waiting.
|
|
58
61
|
if job_id is null and key is not null then
|
package/dist/jobs/runtime.js
CHANGED
|
@@ -81,8 +81,10 @@ const startJobs = async ({ db, jobs, work = true, pollSeconds = 2, shutdownSecon
|
|
|
81
81
|
const checked = await validatePayload(definition, payload);
|
|
82
82
|
if ("invalid" in checked) throw new Error(checked.invalid);
|
|
83
83
|
const data = checked.value ?? null;
|
|
84
|
+
const orderedId = definition.options.ordered ? (await sql`select uuidv7() as id`.execute(target)).rows[0].id : void 0;
|
|
84
85
|
const send = {
|
|
85
86
|
...sendOptions(definition.options, options),
|
|
87
|
+
...orderedId !== void 0 && { id: orderedId },
|
|
86
88
|
db: jobsDatabase(target)
|
|
87
89
|
};
|
|
88
90
|
const keyed = async (key) => {
|
package/dist/meta.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { seesAssistant } from "./assistant/assistant-settings.js";
|
|
2
2
|
import { sha256Hex, stableJson } from "./hash.js";
|
|
3
3
|
import { requestAccess } from "./request-access.js";
|
|
4
|
+
import { activeRole } from "./active-role.js";
|
|
4
5
|
import { seesRuntime } from "./runtime/runtime-settings.js";
|
|
5
6
|
import { pruneView } from "./view-access.js";
|
|
6
7
|
import { prunePage } from "@protobase/layout";
|
|
7
|
-
import { pickView } from "@protobase/schema";
|
|
8
|
+
import { bottomBarFor, pickView } from "@protobase/schema";
|
|
8
9
|
//#region src/meta.ts
|
|
9
10
|
const modelsHash = (deps) => sha256Hex(stableJson(deps.registry.entries.map((entry) => entry.model))).then((hash) => hash.slice(0, 32));
|
|
10
11
|
/**
|
|
11
12
|
* `/meta` as one caller sees it: the resources they can do anything with, each as the restricted model (hidden fields
|
|
12
13
|
* absent, `readOnly` unless writable), the view for their roles with hidden fields pruned, what they may do, and the
|
|
13
|
-
* user menu without the resources they cannot see.
|
|
14
|
+
* user menu and their bottom bar without the resources they cannot see.
|
|
14
15
|
* The ETag hashes all of it, so it differs per user and per roles.
|
|
15
16
|
*/
|
|
16
17
|
const createMeta = (deps) => {
|
|
@@ -32,6 +33,8 @@ const createMeta = (deps) => {
|
|
|
32
33
|
};
|
|
33
34
|
const pages = deps.pages.flatMap((page) => prunePage(page, session.user.roles, callerAccess) ?? []);
|
|
34
35
|
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
|
+
const bar = bottomBarFor(deps.bottomBars, activeRole(session));
|
|
37
|
+
const barItems = bar?.items.filter(shown) ?? [];
|
|
35
38
|
const body = {
|
|
36
39
|
resources: visible.map((access) => access.readable),
|
|
37
40
|
views,
|
|
@@ -48,6 +51,10 @@ const createMeta = (deps) => {
|
|
|
48
51
|
].filter((op) => resolved.operations[op] && (resolved.recordChecks.includes(op) || resolved.rowFilter[op] !== void 0))
|
|
49
52
|
}])),
|
|
50
53
|
...deps.userMenu && { userMenu: { items: deps.userMenu.items.filter(shown) } },
|
|
54
|
+
...bar && barItems.length > 0 && { bottomBar: {
|
|
55
|
+
label: bar.label,
|
|
56
|
+
items: barItems
|
|
57
|
+
} },
|
|
51
58
|
...deps.assistant && seesAssistant(session.user.roles) && { assistant: { url: deps.assistant } },
|
|
52
59
|
...deps.runtime && seesRuntime(session.user.roles) && { runtime: { url: deps.runtime } }
|
|
53
60
|
};
|
|
@@ -64,7 +64,7 @@ const parameters = {
|
|
|
64
64
|
orderBy: {
|
|
65
65
|
name: "order_by",
|
|
66
66
|
in: "query",
|
|
67
|
-
description: "Comma separated sortable fields, each with an optional `desc`, as in [AIP-132](https://google.aip.dev/132#ordering): `
|
|
67
|
+
description: "Comma separated sortable fields, each with an optional `desc`, as in [AIP-132](https://google.aip.dev/132#ordering): `created_at desc, number`. The primary key breaks ties.",
|
|
68
68
|
schema: { type: "string" }
|
|
69
69
|
},
|
|
70
70
|
pageSize: {
|
package/dist/openapi/document.js
CHANGED
|
@@ -2,20 +2,22 @@ import { batchSchemas, errorResponses, parameters, problemSchema, searchBody } f
|
|
|
2
2
|
import { resourcePaths } from "./resource-paths.js";
|
|
3
3
|
import { resourceSchemas } from "./schemas.js";
|
|
4
4
|
//#region src/openapi/document.ts
|
|
5
|
+
const resourcesServer = (basePath) => basePath.slice(basePath.lastIndexOf("/") + 1);
|
|
6
|
+
const systemServer = ".";
|
|
5
7
|
/** The OpenAPI 3.1 document for one caller, generated from the resource models they may see and their zod record schemas. */
|
|
6
|
-
const openApiDocument = (accesses, basePath
|
|
8
|
+
const openApiDocument = (accesses, basePath) => ({
|
|
7
9
|
openapi: "3.1.0",
|
|
8
10
|
info: {
|
|
9
11
|
title: "Protobase API",
|
|
10
12
|
version: "1.0.0",
|
|
11
13
|
description: "Admin API for an existing Postgres database. Follows Google's API design conventions ([AIP](https://google.aip.dev)) and reports errors as RFC 9457 `application/problem+json`."
|
|
12
14
|
},
|
|
13
|
-
servers: [{ url: basePath }],
|
|
15
|
+
servers: [{ url: resourcesServer(basePath) }],
|
|
14
16
|
security: [{ bearer: [] }],
|
|
15
17
|
tags: accesses.map(({ entry }) => ({ name: entry.name })),
|
|
16
18
|
paths: {
|
|
17
19
|
"/meta": {
|
|
18
|
-
servers: [{ url:
|
|
20
|
+
servers: [{ url: systemServer }],
|
|
19
21
|
get: {
|
|
20
22
|
operationId: "get_meta",
|
|
21
23
|
summary: "Resource and view models",
|
|
@@ -27,8 +29,8 @@ const openApiDocument = (accesses, basePath, systemPath) => ({
|
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
},
|
|
30
|
-
[`/${
|
|
31
|
-
servers: [{ url:
|
|
32
|
+
[`/${resourcesServer(basePath)}:batchWrite`]: {
|
|
33
|
+
servers: [{ url: systemServer }],
|
|
32
34
|
post: {
|
|
33
35
|
operationId: "batch_write",
|
|
34
36
|
summary: "Write many records in one transaction",
|
package/dist/openapi/naming.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//#region src/openapi/naming.ts
|
|
2
|
-
|
|
2
|
+
/** A component name from a resource name: `stock_moves` and `stockMoves` both become `StockMoves`. */
|
|
3
|
+
const pascal = (name) => name.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
3
4
|
//#endregion
|
|
4
5
|
export { pascal };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SubscriptionDefinition } from "./webhooks/subscription.js";
|
|
2
2
|
import "./index.js";
|
|
3
3
|
import { PageDefinition } from "@protobase/layout";
|
|
4
|
-
import { AccessSource, EventMatch, FileProcessor, UserMenuSource, ViewModel } from "@protobase/schema";
|
|
4
|
+
import { AccessSource, BottomBarSource, EventMatch, FileProcessor, UserMenuSource, ViewModel } from "@protobase/schema";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
//#region src/resource-source.d.ts
|
|
7
7
|
type FieldSource = {
|
|
@@ -29,7 +29,7 @@ export type ResourceSource = AccessSource & {
|
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
31
|
* Splits a config module (`import * as config from './config'`) into its resources, views, pages, subscriptions and,
|
|
32
|
-
* when it exports one `userMenu(...)`, the user menu.
|
|
32
|
+
* when it exports one `userMenu(...)`, the user menu, and its `bottomBar(...)` exports in order.
|
|
33
33
|
*/
|
|
34
34
|
export declare const configExports: (module: Record<string, unknown>) => {
|
|
35
35
|
userMenu?: UserMenuSource | undefined;
|
|
@@ -39,5 +39,6 @@ export declare const configExports: (module: Record<string, unknown>) => {
|
|
|
39
39
|
}>;
|
|
40
40
|
pages: PageDefinition[];
|
|
41
41
|
subscriptions: SubscriptionDefinition[];
|
|
42
|
+
bottomBars: BottomBarSource[];
|
|
42
43
|
};
|
|
43
44
|
//#endregion
|
package/dist/resource-source.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isPageDefinition } from "@protobase/layout";
|
|
|
3
3
|
//#region src/resource-source.ts
|
|
4
4
|
/**
|
|
5
5
|
* Splits a config module (`import * as config from './config'`) into its resources, views, pages, subscriptions and,
|
|
6
|
-
* when it exports one `userMenu(...)`, the user menu.
|
|
6
|
+
* when it exports one `userMenu(...)`, the user menu, and its `bottomBar(...)` exports in order.
|
|
7
7
|
*/
|
|
8
8
|
const configExports = (module) => {
|
|
9
9
|
const values = Object.values(module);
|
|
@@ -12,12 +12,14 @@ const configExports = (module) => {
|
|
|
12
12
|
const others = values.filter((value) => !isPageDefinition(value) && !isSubscription(value));
|
|
13
13
|
const buildable = others.filter((value) => typeof value?.toModel === "function");
|
|
14
14
|
const menus = others.filter((value) => typeof value?.toUserMenuModel === "function");
|
|
15
|
+
const bottomBars = [...new Set(others.filter((value) => typeof value?.toBottomBarModel === "function"))];
|
|
15
16
|
if (menus.length > 1) throw new Error(`The config module exports ${menus.length} user menus; export one userMenu(...)`);
|
|
16
17
|
return {
|
|
17
18
|
resources: buildable.filter((value) => typeof value.recordSchema === "function"),
|
|
18
19
|
views: buildable.filter((value) => typeof value.recordSchema !== "function"),
|
|
19
20
|
pages,
|
|
20
21
|
subscriptions,
|
|
22
|
+
bottomBars,
|
|
21
23
|
...menus[0] && { userMenu: menus[0] }
|
|
22
24
|
};
|
|
23
25
|
};
|
package/dist/routes/docs.js
CHANGED
|
@@ -8,10 +8,10 @@ const docsRoutes = (deps) => {
|
|
|
8
8
|
const app = new Hono();
|
|
9
9
|
app.get("/openapi.json", async (c) => {
|
|
10
10
|
const visible = (await Promise.all(deps.registry.entries.map((entry) => requestAccess(deps, entry, c.get("session"))))).filter((access) => Object.values(access.resolved.operations).some(Boolean));
|
|
11
|
-
return c.json(openApiDocument(visible, deps.basePath
|
|
11
|
+
return c.json(openApiDocument(visible, deps.basePath));
|
|
12
12
|
});
|
|
13
13
|
app.get("/docs", Scalar({
|
|
14
|
-
url:
|
|
14
|
+
url: "openapi.json",
|
|
15
15
|
pageTitle: "Protobase API"
|
|
16
16
|
}));
|
|
17
17
|
return app;
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import { parseRoles } from "../../better-auth/parse-roles.js";
|
|
2
2
|
import { effectiveRoles, globalRoles } from "../../better-auth/organizations/app-roles.js";
|
|
3
3
|
import { findMember } from "../../better-auth/organizations/store.js";
|
|
4
|
+
import { resolveActiveRole } from "../../better-auth/roles/active-role.js";
|
|
4
5
|
//#region src/webhooks/table/owner-roles.ts
|
|
5
|
-
|
|
6
|
-
* The roles someone holds now, as their next token would carry them: their global roles and, with organizations, their
|
|
7
|
-
* app roles as a member of the tenant. None for a user who is banned or gone.
|
|
8
|
-
*/
|
|
9
|
-
const betterAuthOwnerRoles = (auth) => async ({ id, tenant }) => {
|
|
10
|
-
const { adapter, internalAdapter } = await auth.$context;
|
|
11
|
-
const user = await internalAdapter.findUserById(id);
|
|
12
|
-
if (!user || user.banned) return [];
|
|
6
|
+
const heldIn = async (auth, user, tenant) => {
|
|
13
7
|
if (!auth.organizations) return parseRoles(user.role);
|
|
14
8
|
const global = globalRoles(user.role);
|
|
15
9
|
if (tenant === void 0) return global;
|
|
10
|
+
const { adapter } = await auth.$context;
|
|
16
11
|
const member = await findMember(adapter, {
|
|
17
12
|
organizationId: String(tenant),
|
|
18
|
-
userId: id
|
|
13
|
+
userId: user.id
|
|
19
14
|
});
|
|
20
15
|
return member ? effectiveRoles(global, member.appRoles) : global;
|
|
21
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* The role someone acts with now, as their next session's token would carry it: the one they last chose while they
|
|
19
|
+
* hold it, else their first (see `resolveActiveRole`). None for a user who is banned or gone, or holds no role.
|
|
20
|
+
*/
|
|
21
|
+
const betterAuthOwnerRoles = (auth) => async ({ id, tenant }) => {
|
|
22
|
+
const { internalAdapter } = await auth.$context;
|
|
23
|
+
const user = await internalAdapter.findUserById(id);
|
|
24
|
+
if (!user || user.banned) return [];
|
|
25
|
+
const active = resolveActiveRole(await heldIn(auth, user, tenant), [user.lastRole]);
|
|
26
|
+
return active === void 0 ? [] : [active];
|
|
27
|
+
};
|
|
22
28
|
//#endregion
|
|
23
29
|
export { betterAuthOwnerRoles };
|
|
@@ -4,7 +4,7 @@ import { ProjectConfig } from "../../project-config.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* Webhook subscriptions made in the admin app: `extends: [webhooks()]` in `protobase.config.ts`. It adds the Webhook
|
|
6
6
|
* subscriptions and Webhook deliveries pages, over a `webhooks` schema that `protobase migration` writes. Who may
|
|
7
|
-
* create subscriptions is the resources' access (`
|
|
7
|
+
* create subscriptions is the resources' access (`webhook_subscriptions.create`, ...); each delivers as its owner.
|
|
8
8
|
*/
|
|
9
9
|
export declare const webhooks: (options?: WebhooksOptions) => ProjectConfig;
|
|
10
10
|
//#endregion
|
|
@@ -4,7 +4,7 @@ import { webhookResources } from "@protobase/schema";
|
|
|
4
4
|
/**
|
|
5
5
|
* Webhook subscriptions made in the admin app: `extends: [webhooks()]` in `protobase.config.ts`. It adds the Webhook
|
|
6
6
|
* subscriptions and Webhook deliveries pages, over a `webhooks` schema that `protobase migration` writes. Who may
|
|
7
|
-
* create subscriptions is the resources' access (`
|
|
7
|
+
* create subscriptions is the resources' access (`webhook_subscriptions.create`, ...); each delivers as its owner.
|
|
8
8
|
*/
|
|
9
9
|
const webhooks = (options = {}) => {
|
|
10
10
|
const schema = webhooksSchema(options);
|
|
@@ -8,7 +8,7 @@ const isHeaders = (value) => value === null || value === void 0 || typeof value
|
|
|
8
8
|
* it covers, headers of text, and a URL at a public address. A refusal is a 400 problem, and the write rolls back.
|
|
9
9
|
*/
|
|
10
10
|
const subscriptionWriteCheck = (models, checkUrl) => async (event) => {
|
|
11
|
-
if (event.resource.name !== "
|
|
11
|
+
if (event.resource.name !== "webhook_subscriptions" || !event.after) return;
|
|
12
12
|
const { events, url, filter, headers } = event.after;
|
|
13
13
|
const candidate = {
|
|
14
14
|
kind: "subscription",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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.
|
|
34
|
-
"@protobase/query": "0.
|
|
35
|
-
"@protobase/schema": "0.
|
|
33
|
+
"@protobase/layout": "0.10.0",
|
|
34
|
+
"@protobase/query": "0.10.0",
|
|
35
|
+
"@protobase/schema": "0.10.0",
|
|
36
36
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
37
37
|
"@simplewebauthn/server": "^13.3.1",
|
|
38
38
|
"better-auth": "^1.7.7",
|