deepspace 0.20.0 → 0.22.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/CHANGELOG.md +28 -0
- package/dist/{chunk-A7UFIOWO.js → chunk-7TDBFEB7.js} +7 -2
- package/dist/chunk-7TDBFEB7.js.map +1 -0
- package/dist/cli.js +288 -120
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.d.ts +3 -2
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +48 -48
- package/dist/documentation-react.d.ts +2 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +7 -7
- package/dist/documentation-server-core.d.ts +3 -2
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.d.ts +40 -12
- package/dist/documentation.js +40 -7
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +225 -21
- package/dist/index.js +239 -100
- package/dist/index.js.map +1 -1
- package/dist/{public-CFAj1hL2.d.ts → public-DenQ1TsZ.d.ts} +36 -11
- package/dist/server.d.ts +32 -4
- package/dist/server.js +177 -43
- package/dist/server.js.map +1 -1
- package/dist/testing-mcp.d.ts +69 -0
- package/dist/testing-mcp.js +99 -0
- package/dist/testing-mcp.js.map +1 -0
- package/dist/testing.d.ts +17 -20
- package/dist/testing.js +47 -25
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +57 -5
- package/dist/worker.js +262 -62
- package/dist/worker.js.map +1 -1
- package/features/ai-chat/feature.json +2 -2
- package/features/ai-chat/src/AiChatPage.tsx +56 -21
- package/features/ai-chat/src/ChatPanel.tsx +33 -10
- package/features/ai-chat/src/__tests__/ChatPanel.lifecycle.test.tsx +156 -0
- package/features/cron/src/CronLogPage.tsx +107 -69
- package/features/file-attachments/feature.json +2 -1
- package/features/file-manager/feature.json +2 -1
- package/features/file-manager/src/FileManagerPage.tsx +227 -194
- package/features/integration-test/src/IntegrationTestPage.tsx +54 -34
- package/package.json +5 -1
- package/dist/chunk-A7UFIOWO.js.map +0 -1
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { ReactNode, ReactElement, ComponentType } from 'react';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
declare const themeObjectSchema: z.ZodObject<{
|
|
5
|
+
accent: z.ZodOptional<z.ZodString>;
|
|
6
|
+
accentDark: z.ZodOptional<z.ZodString>;
|
|
7
|
+
background: z.ZodOptional<z.ZodString>;
|
|
8
|
+
density: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
comfortable: "comfortable";
|
|
10
|
+
compact: "compact";
|
|
11
|
+
}>>;
|
|
12
|
+
logo: z.ZodOptional<z.ZodString>;
|
|
13
|
+
logoDark: z.ZodOptional<z.ZodString>;
|
|
14
|
+
favicon: z.ZodOptional<z.ZodString>;
|
|
15
|
+
defaultMode: z.ZodOptional<z.ZodEnum<{
|
|
16
|
+
light: "light";
|
|
17
|
+
dark: "dark";
|
|
18
|
+
system: "system";
|
|
19
|
+
}>>;
|
|
20
|
+
strictMode: z.ZodOptional<z.ZodBoolean>;
|
|
21
|
+
}, z.core.$strip>;
|
|
2
22
|
|
|
3
23
|
type DocumentationAssistantAccess = 'disabled' | 'public' | 'authenticated';
|
|
4
24
|
type DocumentationMcpAccess = 'disabled' | 'public';
|
|
@@ -10,11 +30,21 @@ interface DocumentationFontConfig {
|
|
|
10
30
|
source?: string;
|
|
11
31
|
format?: string;
|
|
12
32
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
33
|
+
/**
|
|
34
|
+
* The `theme` object as authored in documentation.json — exactly the keys
|
|
35
|
+
* the config schema accepts under `theme.*`, derived from that schema so
|
|
36
|
+
* the two can never drift. Everything else (fonts, background decoration,
|
|
37
|
+
* styling, logo href) is configured through the Mintlify-style top-level
|
|
38
|
+
* keys and only exists on the resolved theme.
|
|
39
|
+
*/
|
|
40
|
+
type DocumentationThemeConfig = z.infer<typeof themeObjectSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* The fully resolved theme after config loading merges `theme.*` with the
|
|
43
|
+
* Mintlify top-level keys (`colors`, `logo`, `favicon`, `appearance`,
|
|
44
|
+
* `background`, `fonts`, `styling`). This is what the template and runtime
|
|
45
|
+
* consume; it is an output shape, never accepted as `theme.*` input.
|
|
46
|
+
*/
|
|
47
|
+
interface ResolvedDocumentationTheme extends DocumentationThemeConfig {
|
|
18
48
|
backgroundDark?: string;
|
|
19
49
|
backgroundDecoration?: 'none' | 'gradient' | 'grid';
|
|
20
50
|
bodyFont?: DocumentationFontConfig;
|
|
@@ -22,12 +52,7 @@ interface DocumentationThemeConfig {
|
|
|
22
52
|
monoFont?: DocumentationFontConfig;
|
|
23
53
|
codeBlockMode?: 'dark' | 'system';
|
|
24
54
|
eyebrowStyle?: 'section' | 'breadcrumbs' | 'none';
|
|
25
|
-
logo?: string;
|
|
26
|
-
logoDark?: string;
|
|
27
55
|
logoHref?: string;
|
|
28
|
-
favicon?: string;
|
|
29
|
-
defaultMode?: 'light' | 'dark' | 'system';
|
|
30
|
-
strictMode?: boolean;
|
|
31
56
|
}
|
|
32
57
|
interface DocumentationLinkConfig {
|
|
33
58
|
label: string;
|
|
@@ -79,7 +104,7 @@ interface DocumentationConfig {
|
|
|
79
104
|
url?: string;
|
|
80
105
|
/** Explicit custom hostnames that mount this documentation at `/`. */
|
|
81
106
|
domains: string[];
|
|
82
|
-
theme:
|
|
107
|
+
theme: ResolvedDocumentationTheme;
|
|
83
108
|
navigation?: DocumentationNavigationItem[];
|
|
84
109
|
links: DocumentationLinkConfig[];
|
|
85
110
|
footer: DocumentationLinkConfig[];
|
package/dist/server.d.ts
CHANGED
|
@@ -75,6 +75,13 @@ declare const APP_ID_RE: RegExp;
|
|
|
75
75
|
declare const STRICT_APP_ID_RE: RegExp;
|
|
76
76
|
/** Internal physical locators survive identity migration and are not public ids. */
|
|
77
77
|
declare const RESOURCE_ID_RE: RegExp;
|
|
78
|
+
/** A 26-char ULID (48-bit ms timestamp + 80 random bits, Crockford base32) —
|
|
79
|
+
* the id shape shared by app ids (`app_…`) and workspace ids (`ws_…`). */
|
|
80
|
+
declare function mintUlid(now?: number): string;
|
|
81
|
+
/** Mint a fresh app id: `app_` + 26-char ULID. App ids are minted ONLY by the
|
|
82
|
+
* deploy worker's authenticated `POST /api/apps/mint`, which registers the id
|
|
83
|
+
* to its caller in the same step — an id with no owner never exists. */
|
|
84
|
+
declare function mintAppId(now?: number): string;
|
|
78
85
|
declare class RegistryClientError extends Error {
|
|
79
86
|
readonly code: string;
|
|
80
87
|
readonly status: number;
|
|
@@ -1078,7 +1085,7 @@ declare function composioTools(env: ApiWorkerEnv, options: ComposioToolsOptions)
|
|
|
1078
1085
|
interface ScreenshotEnv extends PlatformWorkerEnv {
|
|
1079
1086
|
/** Immutable app id — the identity the platform verifies (HMAC input). */
|
|
1080
1087
|
DEEPSPACE_APP_ID: string;
|
|
1081
|
-
/** Absent until the app's first deploy
|
|
1088
|
+
/** Absent until the app's first deploy injects it — see appendAppIdentity. */
|
|
1082
1089
|
APP_IDENTITY_TOKEN?: string;
|
|
1083
1090
|
}
|
|
1084
1091
|
interface ScreenshotResult {
|
|
@@ -1532,6 +1539,7 @@ declare const MSG: {
|
|
|
1532
1539
|
readonly CRON_PAUSE: "cron.pause";
|
|
1533
1540
|
readonly CRON_RESUME: "cron.resume";
|
|
1534
1541
|
readonly CRON_STATUS: "cron.status";
|
|
1542
|
+
readonly CRON_ACK: "cron.ack";
|
|
1535
1543
|
readonly JOB_ENQUEUE: "job.enqueue";
|
|
1536
1544
|
readonly JOB_CANCEL: "job.cancel";
|
|
1537
1545
|
readonly JOB_RETRY: "job.retry";
|
|
@@ -1699,6 +1707,16 @@ type ServerMessage = BaseMessage<typeof MSG.QUERY_RESULT, {
|
|
|
1699
1707
|
}> | BaseMessage<typeof MSG.CRON_STATUS, {
|
|
1700
1708
|
tasks: unknown;
|
|
1701
1709
|
recentHistory: unknown;
|
|
1710
|
+
}> | BaseMessage<typeof MSG.CRON_ACK, {
|
|
1711
|
+
requestId: string;
|
|
1712
|
+
taskName: string;
|
|
1713
|
+
ok: true;
|
|
1714
|
+
} | {
|
|
1715
|
+
requestId: string;
|
|
1716
|
+
taskName?: string;
|
|
1717
|
+
ok: false;
|
|
1718
|
+
reason: 'read_only' | 'unknown_task' | 'failed';
|
|
1719
|
+
error?: string;
|
|
1702
1720
|
}> | BaseMessage<typeof MSG.JOB_UPDATE, {
|
|
1703
1721
|
kind: 'snapshot' | 'enqueued' | 'progress' | 'succeeded' | 'failed' | 'canceled' | 'retried';
|
|
1704
1722
|
job?: unknown;
|
|
@@ -2313,12 +2331,22 @@ declare abstract class CronRoom<E = Record<string, unknown>> extends BaseRoom<E>
|
|
|
2313
2331
|
type: string;
|
|
2314
2332
|
[key: string]: unknown;
|
|
2315
2333
|
}): Promise<void>;
|
|
2334
|
+
private dispatchMessage;
|
|
2316
2335
|
protected onAlarm(): Promise<void>;
|
|
2317
2336
|
private executeTask;
|
|
2318
2337
|
private scheduleNextAlarm;
|
|
2319
2338
|
private getTaskStates;
|
|
2320
2339
|
private getRecentHistory;
|
|
2321
2340
|
private broadcastStatus;
|
|
2341
|
+
/**
|
|
2342
|
+
* Receipt for a mutation frame, addressed only to its sender. Receipts
|
|
2343
|
+
* are opt-in by correlation id: frames without a `requestId` keep the
|
|
2344
|
+
* fire-and-forget contract, so the (untyped) `requestId` from the wire
|
|
2345
|
+
* is the single gate here rather than a check at every call site.
|
|
2346
|
+
* Frames go through the shared `serverBuild` constructors so the wire
|
|
2347
|
+
* shape is enforced by the protocol types, not re-spelled here.
|
|
2348
|
+
*/
|
|
2349
|
+
private ackMutation;
|
|
2322
2350
|
/**
|
|
2323
2351
|
* Execute a scheduled task by name.
|
|
2324
2352
|
* Called both by the alarm scheduler and manual trigger.
|
|
@@ -4451,7 +4479,7 @@ interface SubscriptionRead {
|
|
|
4451
4479
|
plans: PlanInfo[];
|
|
4452
4480
|
}
|
|
4453
4481
|
interface StarterAppEnv$1 extends ApiWorkerEnv {
|
|
4454
|
-
/** Absent until the app's first deploy
|
|
4482
|
+
/** Absent until the app's first deploy injects it — see appendAppIdentity. */
|
|
4455
4483
|
APP_IDENTITY_TOKEN?: string;
|
|
4456
4484
|
/** Immutable app id — the identity the platform verifies (HMAC input). */
|
|
4457
4485
|
DEEPSPACE_APP_ID: string;
|
|
@@ -4540,7 +4568,7 @@ declare class CancelSubscriptionError extends Error {
|
|
|
4540
4568
|
}
|
|
4541
4569
|
|
|
4542
4570
|
interface StarterAppEnv extends ApiWorkerEnv {
|
|
4543
|
-
/** Absent until the app's first deploy
|
|
4571
|
+
/** Absent until the app's first deploy injects it — see appendAppIdentity. */
|
|
4544
4572
|
APP_IDENTITY_TOKEN?: string;
|
|
4545
4573
|
/** Immutable app id — the identity the platform verifies (HMAC input). */
|
|
4546
4574
|
DEEPSPACE_APP_ID: string;
|
|
@@ -4565,4 +4593,4 @@ declare class RefundError extends Error {
|
|
|
4565
4593
|
constructor(message: string, status: number);
|
|
4566
4594
|
}
|
|
4567
4595
|
|
|
4568
|
-
export { ACCOUNT_STORAGE_LIMIT_BYTES, AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, COST_RATES, CancelSubscriptionError, type CancelSubscriptionOpts, type CancelSubscriptionResult, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DEPLOYED_APPS_DEFAULTS, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DebugApiContext, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAgentDiagnosticContext, DeepSpaceAgentModelError, DeepSpaceAgentProfileError, type DeepSpaceAgentStream, type DeepSpaceAgentStreamOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GetActionData, type GlobalDOType, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, MAX_APP_FILE_BYTES, MAX_DEPLOY_ASSET_FILE_BYTES, MAX_UPLOAD_PARTS, MAX_UPLOAD_REQUEST_BYTES, MESSAGES_SCHEMA, type MutateActionData, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlanInfo, type PlatformWorkerEnv, type PrefixResult, type PresencePeer, PresenceRoom, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, REGISTRY_INSTANCE, RESERVED_BINDING_NAMES, RESERVED_COLLECTION_NAMES, RESOURCE_ID_RE, type RecordContext, RecordRoom, type RecordRoomConfig, RefundError, type RefundOpts, type RefundResult, RegistryClientError, type ResolvedColumn, type ResolvedPermission, type RolePermissions, type RunMigrationsResult, STRICT_APP_ID_RE, SYSTEM_COLLECTION_SCHEMAS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotResult, type SharedConnection, type StorageAdmission, type StoredRecord, SubscriptionAuthError, type SubscriptionContext, type SubscriptionRead, SubscriptionRequiredError, type SubscriptionStatus, type Summarizer, TEST_ACCOUNT_EMAIL_SUFFIX, type TokenDebugInfo, type ToolResult, type ToolSchema, type ToolsApiContext, UPLOAD_PART_BYTES, USERS_COLUMNS, type User, type UserAttachment, type UserContext, VOTING_SCHEMAS, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, type YjsContext, YjsRoom, analyzePermissions, apiWorkerFetch, appendMessage, applyAiToolDefaults, applySlidingWindow, authWorkerFetch, bindingManifestFromOutputConfig, broadcastChange, broadcastYjsUpdate, buildCronContext, buildTableSelect, buildUiParts, callRegistry, canCreate, canDelete, canRead, canUpdate, cancelSubscription, capToolResultSize, captureScreenshot, checkFieldPermissions, checkUnclaimedOwnerTransition, coerceValue, collectionTableName, columnId, composioTools, computeDoMigration, computeHmacHex, createChat, createDeepSpaceAI, createDeepSpaceAuth, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deepSpaceAgentErrorSummary, deleteChatCascade, deleteRecord, enqueueJob, executeQuery, formatBytes, getAllUsers, getChat, getGlobalDOSchemas, getGlobalDOType, getOrCreateYjsDoc, getRecord, getRolePermissions, getSubscription, getUser, getYjsDocKey, handleApiRequest, handleDelete, handlePut, handleSetRole, handleSubscribe, handleToolsRequest, handleUnsubscribe, handleUserList, handleUserUpdate, handleYjsBinaryMessage, handleYjsJoin, handleYjsLeave, isAutoProvision, isFilesVerbPath, isOwner, isTestAccountClaims, isTestAccountEmail, isTestAccountTier, lintSchema, loadMessages, makeDefaultSummarizer, matchOrigin, meterAi, meterUsage, meterVectorize, noopPermissionContext, parseQuotaLimit, platformCorsPatterns, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, putRecord, readRecord, recordMatchesSubscription, refundInvoice, registerUser, registryErrorJson, registryStub, requireSubscription, resolveAppName, resolveAppRole, resolveColumn, rowToData, runMigrations, saveYjsDoc, storageLimitForTier, storageQuotaMessage, streamDeepSpaceAgent, timingSafeEqualHex, timingSafeEqualStrings, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema };
|
|
4596
|
+
export { ACCOUNT_STORAGE_LIMIT_BYTES, AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, COST_RATES, CancelSubscriptionError, type CancelSubscriptionOpts, type CancelSubscriptionResult, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DEPLOYED_APPS_DEFAULTS, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DebugApiContext, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAgentDiagnosticContext, DeepSpaceAgentModelError, DeepSpaceAgentProfileError, type DeepSpaceAgentStream, type DeepSpaceAgentStreamOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GetActionData, type GlobalDOType, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, MAX_APP_FILE_BYTES, MAX_DEPLOY_ASSET_FILE_BYTES, MAX_UPLOAD_PARTS, MAX_UPLOAD_REQUEST_BYTES, MESSAGES_SCHEMA, type MutateActionData, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlanInfo, type PlatformWorkerEnv, type PrefixResult, type PresencePeer, PresenceRoom, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, REGISTRY_INSTANCE, RESERVED_BINDING_NAMES, RESERVED_COLLECTION_NAMES, RESOURCE_ID_RE, type RecordContext, RecordRoom, type RecordRoomConfig, RefundError, type RefundOpts, type RefundResult, RegistryClientError, type ResolvedColumn, type ResolvedPermission, type RolePermissions, type RunMigrationsResult, STRICT_APP_ID_RE, SYSTEM_COLLECTION_SCHEMAS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotResult, type SharedConnection, type StorageAdmission, type StoredRecord, SubscriptionAuthError, type SubscriptionContext, type SubscriptionRead, SubscriptionRequiredError, type SubscriptionStatus, type Summarizer, TEST_ACCOUNT_EMAIL_SUFFIX, type TokenDebugInfo, type ToolResult, type ToolSchema, type ToolsApiContext, UPLOAD_PART_BYTES, USERS_COLUMNS, type User, type UserAttachment, type UserContext, VOTING_SCHEMAS, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, type YjsContext, YjsRoom, analyzePermissions, apiWorkerFetch, appendMessage, applyAiToolDefaults, applySlidingWindow, authWorkerFetch, bindingManifestFromOutputConfig, broadcastChange, broadcastYjsUpdate, buildCronContext, buildTableSelect, buildUiParts, callRegistry, canCreate, canDelete, canRead, canUpdate, cancelSubscription, capToolResultSize, captureScreenshot, checkFieldPermissions, checkUnclaimedOwnerTransition, coerceValue, collectionTableName, columnId, composioTools, computeDoMigration, computeHmacHex, createChat, createDeepSpaceAI, createDeepSpaceAuth, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deepSpaceAgentErrorSummary, deleteChatCascade, deleteRecord, enqueueJob, executeQuery, formatBytes, getAllUsers, getChat, getGlobalDOSchemas, getGlobalDOType, getOrCreateYjsDoc, getRecord, getRolePermissions, getSubscription, getUser, getYjsDocKey, handleApiRequest, handleDelete, handlePut, handleSetRole, handleSubscribe, handleToolsRequest, handleUnsubscribe, handleUserList, handleUserUpdate, handleYjsBinaryMessage, handleYjsJoin, handleYjsLeave, isAutoProvision, isFilesVerbPath, isOwner, isTestAccountClaims, isTestAccountEmail, isTestAccountTier, lintSchema, loadMessages, makeDefaultSummarizer, matchOrigin, meterAi, meterUsage, meterVectorize, mintAppId, mintUlid, noopPermissionContext, parseQuotaLimit, platformCorsPatterns, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, putRecord, readRecord, recordMatchesSubscription, refundInvoice, registerUser, registryErrorJson, registryStub, requireSubscription, resolveAppName, resolveAppRole, resolveColumn, rowToData, runMigrations, saveYjsDoc, storageLimitForTier, storageQuotaMessage, streamDeepSpaceAgent, timingSafeEqualHex, timingSafeEqualStrings, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema };
|
package/dist/server.js
CHANGED
|
@@ -34,6 +34,32 @@ var REGISTRY_INSTANCE = "v1:global";
|
|
|
34
34
|
var APP_ID_RE = /^app_[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
35
35
|
var STRICT_APP_ID_RE = APP_ID_RE;
|
|
36
36
|
var RESOURCE_ID_RE = /^(app_[0-9A-HJKMNP-TV-Z]{26}|[a-z0-9][a-z0-9_-]{0,63})$/;
|
|
37
|
+
var CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
38
|
+
function mintUlid(now = Date.now()) {
|
|
39
|
+
let ts = "";
|
|
40
|
+
let t = now;
|
|
41
|
+
for (let i = 0; i < 10; i++) {
|
|
42
|
+
ts = CROCKFORD[t % 32] + ts;
|
|
43
|
+
t = Math.floor(t / 32);
|
|
44
|
+
}
|
|
45
|
+
const rand = new Uint8Array(10);
|
|
46
|
+
crypto.getRandomValues(rand);
|
|
47
|
+
let rs = "";
|
|
48
|
+
let acc = 0;
|
|
49
|
+
let bits = 0;
|
|
50
|
+
for (const byte of rand) {
|
|
51
|
+
acc = acc << 8 | byte;
|
|
52
|
+
bits += 8;
|
|
53
|
+
while (bits >= 5) {
|
|
54
|
+
bits -= 5;
|
|
55
|
+
rs += CROCKFORD[acc >> bits & 31];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return `${ts}${rs}`.slice(0, 26);
|
|
59
|
+
}
|
|
60
|
+
function mintAppId(now = Date.now()) {
|
|
61
|
+
return `app_${mintUlid(now)}`;
|
|
62
|
+
}
|
|
37
63
|
var RegistryClientError = class extends Error {
|
|
38
64
|
constructor(message, code, status) {
|
|
39
65
|
super(message);
|
|
@@ -740,6 +766,9 @@ function declaredLength(request, what) {
|
|
|
740
766
|
function isKeyWithinScope(key, prefix, excludedPrefixes) {
|
|
741
767
|
return key.startsWith(prefix) && !excludedPrefixes.some((excluded) => key.startsWith(excluded));
|
|
742
768
|
}
|
|
769
|
+
function scopeRelativeKey(key, prefix) {
|
|
770
|
+
return key.slice(prefix.length);
|
|
771
|
+
}
|
|
743
772
|
function anchorKey(raw, prefix, excludedPrefixes) {
|
|
744
773
|
const safe = sanitizeSubpath(raw);
|
|
745
774
|
if (safe === null) return fail2(400, "Invalid key: traversal not allowed", "invalid_key");
|
|
@@ -939,7 +968,7 @@ async function handleUpload(request, url, bucket, prefix, excludedPrefixes, auth
|
|
|
939
968
|
admission.markerKey,
|
|
940
969
|
admission.markerKey !== null || fileData.byteLength < replacedBytes
|
|
941
970
|
);
|
|
942
|
-
return storedFileJson(located.key, fileName, url, scope);
|
|
971
|
+
return storedFileJson(located.key, prefix, fileName, url, scope);
|
|
943
972
|
} catch (err) {
|
|
944
973
|
const msg = err instanceof Error ? err.message : "Upload failed";
|
|
945
974
|
console.error("[handleUpload] Error:", msg, err instanceof Error ? err.stack : "");
|
|
@@ -961,11 +990,17 @@ function fileMetadata(fileName, userId, reservationId, declaredBytes) {
|
|
|
961
990
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
962
991
|
};
|
|
963
992
|
}
|
|
964
|
-
function storedFileJson(key, name, url, scope) {
|
|
993
|
+
function storedFileJson(key, prefix, name, url, scope) {
|
|
965
994
|
const fileUrl = new URL(`/api/files/${encodeKeyPath(key)}`, url.origin);
|
|
966
995
|
fileUrl.searchParams.set("scope", scope);
|
|
967
996
|
return Response.json(
|
|
968
|
-
{
|
|
997
|
+
{
|
|
998
|
+
success: true,
|
|
999
|
+
key,
|
|
1000
|
+
relativeKey: scopeRelativeKey(key, prefix),
|
|
1001
|
+
url: fileUrl.toString(),
|
|
1002
|
+
name
|
|
1003
|
+
},
|
|
969
1004
|
{ headers: CORS_HEADERS2 }
|
|
970
1005
|
);
|
|
971
1006
|
}
|
|
@@ -1245,7 +1280,7 @@ async function completedReservationObject(bucket, session) {
|
|
|
1245
1280
|
const object = await bucket.head(session.key);
|
|
1246
1281
|
return object?.customMetadata?.reservationId === session.reservationId ? object : null;
|
|
1247
1282
|
}
|
|
1248
|
-
async function finishCompletedMultipart(bucket, session, reservation, object, auth, url, scope) {
|
|
1283
|
+
async function finishCompletedMultipart(bucket, session, reservation, object, auth, url, scope, prefix) {
|
|
1249
1284
|
const declaredMetadata = Number(object.customMetadata?.declaredBytes);
|
|
1250
1285
|
const declaredBytes = reservation?.declaredBytes ?? (Number.isSafeInteger(declaredMetadata) && declaredMetadata >= 0 ? declaredMetadata : MAX_APP_FILE_BYTES);
|
|
1251
1286
|
const refusal = overCeiling(object.size) ?? (object.size > declaredBytes ? fail2(
|
|
@@ -1279,7 +1314,7 @@ async function finishCompletedMultipart(bucket, session, reservation, object, au
|
|
|
1279
1314
|
}
|
|
1280
1315
|
}
|
|
1281
1316
|
const name = object.customMetadata?.originalName ?? session.uploadKey.split("/").pop() ?? "file";
|
|
1282
|
-
return storedFileJson(session.key, name, url, scope);
|
|
1317
|
+
return storedFileJson(session.key, prefix, name, url, scope);
|
|
1283
1318
|
}
|
|
1284
1319
|
async function multipartComplete(request, url, bucket, prefix, excludedPrefixes, auth, scope) {
|
|
1285
1320
|
const body = await readControlJson(request);
|
|
@@ -1300,7 +1335,7 @@ async function multipartComplete(request, url, bucket, prefix, excludedPrefixes,
|
|
|
1300
1335
|
if (auth.storage && !reservation) {
|
|
1301
1336
|
const completed = await completedReservationObject(bucket, session);
|
|
1302
1337
|
if (completed) {
|
|
1303
|
-
return finishCompletedMultipart(bucket, session, null, completed, auth, url, scope);
|
|
1338
|
+
return finishCompletedMultipart(bucket, session, null, completed, auth, url, scope, prefix);
|
|
1304
1339
|
}
|
|
1305
1340
|
await abandonMultipart(bucket, session, auth, null);
|
|
1306
1341
|
return quotaUnavailable("This upload reservation is missing or does not match.");
|
|
@@ -1339,14 +1374,23 @@ async function multipartComplete(request, url, bucket, prefix, excludedPrefixes,
|
|
|
1339
1374
|
} catch (error) {
|
|
1340
1375
|
const completed = await completedReservationObject(bucket, session);
|
|
1341
1376
|
if (completed) {
|
|
1342
|
-
return finishCompletedMultipart(
|
|
1377
|
+
return finishCompletedMultipart(
|
|
1378
|
+
bucket,
|
|
1379
|
+
session,
|
|
1380
|
+
reservation,
|
|
1381
|
+
completed,
|
|
1382
|
+
auth,
|
|
1383
|
+
url,
|
|
1384
|
+
scope,
|
|
1385
|
+
prefix
|
|
1386
|
+
);
|
|
1343
1387
|
}
|
|
1344
1388
|
if (r2ErrorCode(error) === 10024 && reservation) {
|
|
1345
1389
|
await releaseQuotaMarker(bucket, auth.storage, reservation.key, true);
|
|
1346
1390
|
}
|
|
1347
1391
|
return multipartFailure(error);
|
|
1348
1392
|
}
|
|
1349
|
-
return finishCompletedMultipart(bucket, session, reservation, object, auth, url, scope);
|
|
1393
|
+
return finishCompletedMultipart(bucket, session, reservation, object, auth, url, scope, prefix);
|
|
1350
1394
|
}
|
|
1351
1395
|
async function multipartAbort(url, bucket, prefix, excludedPrefixes, auth) {
|
|
1352
1396
|
const session = resolveSession(url, prefix, excludedPrefixes);
|
|
@@ -1366,37 +1410,49 @@ async function handleList(bucket, prefix, excludedPrefixes, url, scope, auth) {
|
|
|
1366
1410
|
const listPrefix = `${prefix}${userPrefix}`;
|
|
1367
1411
|
const requestedLimit = Number(url.searchParams.get("limit") ?? 100);
|
|
1368
1412
|
const limit = Number.isSafeInteger(requestedLimit) ? Math.min(1e3, Math.max(1, requestedLimit)) : 100;
|
|
1413
|
+
const requestCursor = url.searchParams.get("cursor");
|
|
1369
1414
|
if (excludedPrefixes.some((excluded) => listPrefix.startsWith(excluded))) {
|
|
1370
1415
|
return Response.json({ files: [], truncated: false }, { headers: CORS_HEADERS2 });
|
|
1371
1416
|
}
|
|
1372
|
-
const
|
|
1417
|
+
const withMetadata = (options) => ({ ...options, include: ["customMetadata"] });
|
|
1418
|
+
const listed = await bucket.list(
|
|
1419
|
+
withMetadata({
|
|
1420
|
+
prefix: listPrefix,
|
|
1421
|
+
limit,
|
|
1422
|
+
...requestCursor ? { cursor: requestCursor } : {}
|
|
1423
|
+
})
|
|
1424
|
+
);
|
|
1373
1425
|
const visible = listed.objects.filter(
|
|
1374
1426
|
(object) => isKeyWithinScope(object.key, prefix, excludedPrefixes)
|
|
1375
1427
|
);
|
|
1376
1428
|
const seen = new Set(visible.map((object) => object.key));
|
|
1377
|
-
let
|
|
1378
|
-
|
|
1379
|
-
|
|
1429
|
+
let frontier = listed;
|
|
1430
|
+
let frontierKey = listed.objects.at(-1)?.key;
|
|
1431
|
+
for (const excluded of excludedPrefixes.filter((candidate) => candidate.startsWith(listPrefix)).sort()) {
|
|
1432
|
+
if (!frontier.truncated || visible.length >= limit) break;
|
|
1380
1433
|
const excludedEnd = `${excluded}\u{10FFFF}`;
|
|
1381
|
-
const
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1434
|
+
const after = await bucket.list(
|
|
1435
|
+
withMetadata({
|
|
1436
|
+
prefix: listPrefix,
|
|
1437
|
+
startAfter: frontierKey && frontierKey > excludedEnd ? frontierKey : excludedEnd,
|
|
1438
|
+
limit: limit - visible.length
|
|
1439
|
+
})
|
|
1440
|
+
);
|
|
1387
1441
|
for (const object of after.objects) {
|
|
1388
1442
|
if (!seen.has(object.key) && isKeyWithinScope(object.key, prefix, excludedPrefixes)) {
|
|
1389
1443
|
seen.add(object.key);
|
|
1390
1444
|
visible.push(object);
|
|
1391
1445
|
}
|
|
1392
1446
|
}
|
|
1393
|
-
|
|
1447
|
+
frontierKey = after.objects.at(-1)?.key ?? frontierKey;
|
|
1448
|
+
frontier = after;
|
|
1394
1449
|
}
|
|
1395
1450
|
const files = visible.slice(0, limit).map((obj) => {
|
|
1396
1451
|
const fileUrl = new URL(`/api/files/${encodeKeyPath(obj.key)}`, url.origin);
|
|
1397
1452
|
fileUrl.searchParams.set("scope", scope);
|
|
1398
1453
|
return {
|
|
1399
1454
|
key: obj.key,
|
|
1455
|
+
relativeKey: scopeRelativeKey(obj.key, prefix),
|
|
1400
1456
|
size: obj.size,
|
|
1401
1457
|
uploaded: obj.uploaded.toISOString(),
|
|
1402
1458
|
url: fileUrl.toString(),
|
|
@@ -1411,7 +1467,12 @@ async function handleList(bucket, prefix, excludedPrefixes, url, scope, auth) {
|
|
|
1411
1467
|
if (storage && limitBytes !== null) storage.limitBytes = limitBytes;
|
|
1412
1468
|
}
|
|
1413
1469
|
return Response.json(
|
|
1414
|
-
{
|
|
1470
|
+
{
|
|
1471
|
+
files,
|
|
1472
|
+
truncated: frontier.truncated,
|
|
1473
|
+
...frontier.truncated ? { cursor: frontier.cursor } : {},
|
|
1474
|
+
...storage ? { storage } : {}
|
|
1475
|
+
},
|
|
1415
1476
|
{ headers: CORS_HEADERS2 }
|
|
1416
1477
|
);
|
|
1417
1478
|
}
|
|
@@ -2952,6 +3013,9 @@ var MSG = {
|
|
|
2952
3013
|
CRON_PAUSE: "cron.pause",
|
|
2953
3014
|
CRON_RESUME: "cron.resume",
|
|
2954
3015
|
CRON_STATUS: "cron.status",
|
|
3016
|
+
// Per-mutation receipt, sent only to the socket whose trigger/pause/
|
|
3017
|
+
// resume carried a `requestId` — frames without one stay fire-and-forget.
|
|
3018
|
+
CRON_ACK: "cron.ack",
|
|
2955
3019
|
// ---- JobRoom ---------------------------------------------------------
|
|
2956
3020
|
// Background-job queue with durable, alarm-driven execution. See
|
|
2957
3021
|
// server/rooms/job-room.ts. Clients enqueue and subscribe to updates;
|
|
@@ -3453,6 +3517,14 @@ var serverBuild = {
|
|
|
3453
3517
|
cronTasks: (tasks) => ({ type: MSG.CRON_TASKS, payload: { tasks } }),
|
|
3454
3518
|
cronHistory: (history) => ({ type: MSG.CRON_HISTORY, payload: { history } }),
|
|
3455
3519
|
cronStatus: (tasks, recentHistory) => ({ type: MSG.CRON_STATUS, payload: { tasks, recentHistory } }),
|
|
3520
|
+
cronAckSuccess: (requestId, taskName) => ({
|
|
3521
|
+
type: MSG.CRON_ACK,
|
|
3522
|
+
payload: { requestId, taskName, ok: true }
|
|
3523
|
+
}),
|
|
3524
|
+
cronAckFailure: (requestId, reason, error, taskName) => ({
|
|
3525
|
+
type: MSG.CRON_ACK,
|
|
3526
|
+
payload: { requestId, taskName, ok: false, reason, error }
|
|
3527
|
+
}),
|
|
3456
3528
|
// Jobs
|
|
3457
3529
|
jobSnapshot: (jobs) => ({ type: MSG.JOB_UPDATE, payload: { kind: "snapshot", jobs } }),
|
|
3458
3530
|
jobEnqueued: (job, requestId) => ({
|
|
@@ -6196,40 +6268,88 @@ var CronRoom = class extends BaseRoom {
|
|
|
6196
6268
|
}
|
|
6197
6269
|
async onMessage(ws, user, message) {
|
|
6198
6270
|
this.ensureInitialized();
|
|
6199
|
-
const { type, payload } = message;
|
|
6271
|
+
const { type, payload = {} } = message;
|
|
6200
6272
|
if (CRON_WRITE_TYPES.has(type) && !user.canWrite) {
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6273
|
+
const error = "Write access denied: viewer role cannot modify cron tasks";
|
|
6274
|
+
this.sendTo(ws, { type: MSG.ERROR, payload: { error } });
|
|
6275
|
+
this.ackMutation(ws, payload.requestId, {
|
|
6276
|
+
ok: false,
|
|
6277
|
+
taskName: payload.taskName,
|
|
6278
|
+
reason: "read_only",
|
|
6279
|
+
error
|
|
6204
6280
|
});
|
|
6205
6281
|
return;
|
|
6206
6282
|
}
|
|
6283
|
+
try {
|
|
6284
|
+
await this.dispatchMessage(ws, type, payload);
|
|
6285
|
+
} catch (error) {
|
|
6286
|
+
try {
|
|
6287
|
+
this.ackMutation(ws, payload.requestId, {
|
|
6288
|
+
ok: false,
|
|
6289
|
+
taskName: payload.taskName,
|
|
6290
|
+
reason: "failed",
|
|
6291
|
+
error: error instanceof Error ? error.message : String(error)
|
|
6292
|
+
});
|
|
6293
|
+
} catch {
|
|
6294
|
+
}
|
|
6295
|
+
throw error;
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
async dispatchMessage(ws, type, payload) {
|
|
6207
6299
|
switch (type) {
|
|
6208
6300
|
case MSG.CRON_TRIGGER: {
|
|
6209
6301
|
const taskName = payload.taskName;
|
|
6210
6302
|
if (!taskName) {
|
|
6211
|
-
|
|
6303
|
+
const error = "Missing taskName";
|
|
6304
|
+
this.sendTo(ws, { type: MSG.ERROR, payload: { error } });
|
|
6305
|
+
this.ackMutation(ws, payload.requestId, { ok: false, reason: "failed", error });
|
|
6212
6306
|
return;
|
|
6213
6307
|
}
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6308
|
+
const execution = await this.executeTask(taskName);
|
|
6309
|
+
if (!execution) {
|
|
6310
|
+
const error = `Unknown cron task: ${taskName}`;
|
|
6311
|
+
this.sendTo(ws, { type: MSG.ERROR, payload: { error } });
|
|
6312
|
+
this.ackMutation(ws, payload.requestId, {
|
|
6313
|
+
ok: false,
|
|
6314
|
+
taskName,
|
|
6315
|
+
reason: "unknown_task",
|
|
6316
|
+
error
|
|
6218
6317
|
});
|
|
6318
|
+
break;
|
|
6219
6319
|
}
|
|
6320
|
+
this.ackMutation(
|
|
6321
|
+
ws,
|
|
6322
|
+
payload.requestId,
|
|
6323
|
+
execution.success ? { ok: true, taskName } : { ok: false, taskName, reason: "failed", error: execution.error }
|
|
6324
|
+
);
|
|
6220
6325
|
break;
|
|
6221
6326
|
}
|
|
6222
|
-
case MSG.CRON_PAUSE:
|
|
6223
|
-
const taskName = payload.taskName;
|
|
6224
|
-
this.sql.exec(`UPDATE cron_tasks SET paused = 1 WHERE name = ?`, taskName);
|
|
6225
|
-
this.broadcastStatus();
|
|
6226
|
-
break;
|
|
6227
|
-
}
|
|
6327
|
+
case MSG.CRON_PAUSE:
|
|
6228
6328
|
case MSG.CRON_RESUME: {
|
|
6229
6329
|
const taskName = payload.taskName;
|
|
6230
|
-
|
|
6231
|
-
|
|
6330
|
+
if (!taskName) {
|
|
6331
|
+
const error = "Missing taskName";
|
|
6332
|
+
this.sendTo(ws, { type: MSG.ERROR, payload: { error } });
|
|
6333
|
+
this.ackMutation(ws, payload.requestId, { ok: false, reason: "failed", error });
|
|
6334
|
+
return;
|
|
6335
|
+
}
|
|
6336
|
+
const known = this.sql.exec(`SELECT name FROM cron_tasks WHERE name = ?`, taskName).toArray().length > 0;
|
|
6337
|
+
if (!known) {
|
|
6338
|
+
const error = `Unknown cron task: ${taskName}`;
|
|
6339
|
+
this.sendTo(ws, { type: MSG.ERROR, payload: { error } });
|
|
6340
|
+
this.ackMutation(ws, payload.requestId, {
|
|
6341
|
+
ok: false,
|
|
6342
|
+
taskName,
|
|
6343
|
+
reason: "unknown_task",
|
|
6344
|
+
error
|
|
6345
|
+
});
|
|
6346
|
+
break;
|
|
6347
|
+
}
|
|
6348
|
+
const paused = type === MSG.CRON_PAUSE;
|
|
6349
|
+
this.sql.exec(`UPDATE cron_tasks SET paused = ? WHERE name = ?`, paused ? 1 : 0, taskName);
|
|
6350
|
+
if (!paused) this.scheduleNextAlarm();
|
|
6232
6351
|
this.broadcastStatus();
|
|
6352
|
+
this.ackMutation(ws, payload.requestId, { ok: true, taskName });
|
|
6233
6353
|
break;
|
|
6234
6354
|
}
|
|
6235
6355
|
case MSG.CRON_TASKS: {
|
|
@@ -6272,7 +6392,7 @@ var CronRoom = class extends BaseRoom {
|
|
|
6272
6392
|
// ==========================================================================
|
|
6273
6393
|
async executeTask(taskName) {
|
|
6274
6394
|
const taskRow = this.sql.exec(`SELECT interval_minutes, schedule, timezone FROM cron_tasks WHERE name = ?`, taskName).toArray()[0];
|
|
6275
|
-
if (!taskRow) return
|
|
6395
|
+
if (!taskRow) return null;
|
|
6276
6396
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6277
6397
|
const start = Date.now();
|
|
6278
6398
|
let success = true;
|
|
@@ -6308,7 +6428,7 @@ var CronRoom = class extends BaseRoom {
|
|
|
6308
6428
|
`DELETE FROM cron_history WHERE id NOT IN (SELECT id FROM cron_history ORDER BY id DESC LIMIT 500)`
|
|
6309
6429
|
);
|
|
6310
6430
|
this.broadcastStatus();
|
|
6311
|
-
return
|
|
6431
|
+
return { taskName, startedAt, completedAt, success, durationMs, error };
|
|
6312
6432
|
}
|
|
6313
6433
|
// ==========================================================================
|
|
6314
6434
|
// Scheduling
|
|
@@ -6378,6 +6498,21 @@ var CronRoom = class extends BaseRoom {
|
|
|
6378
6498
|
}
|
|
6379
6499
|
});
|
|
6380
6500
|
}
|
|
6501
|
+
/**
|
|
6502
|
+
* Receipt for a mutation frame, addressed only to its sender. Receipts
|
|
6503
|
+
* are opt-in by correlation id: frames without a `requestId` keep the
|
|
6504
|
+
* fire-and-forget contract, so the (untyped) `requestId` from the wire
|
|
6505
|
+
* is the single gate here rather than a check at every call site.
|
|
6506
|
+
* Frames go through the shared `serverBuild` constructors so the wire
|
|
6507
|
+
* shape is enforced by the protocol types, not re-spelled here.
|
|
6508
|
+
*/
|
|
6509
|
+
ackMutation(ws, requestId, result) {
|
|
6510
|
+
if (typeof requestId !== "string") return;
|
|
6511
|
+
this.sendTo(
|
|
6512
|
+
ws,
|
|
6513
|
+
result.ok ? serverBuild.cronAckSuccess(requestId, result.taskName) : serverBuild.cronAckFailure(requestId, result.reason, result.error, result.taskName)
|
|
6514
|
+
);
|
|
6515
|
+
}
|
|
6381
6516
|
};
|
|
6382
6517
|
function computeNextRunAt(task, from) {
|
|
6383
6518
|
if (task.interval_minutes) {
|
|
@@ -8376,10 +8511,7 @@ async function cancelSubscription(c, opts) {
|
|
|
8376
8511
|
});
|
|
8377
8512
|
if (!res.ok) {
|
|
8378
8513
|
const body = await res.json().catch(() => ({}));
|
|
8379
|
-
throw new CancelSubscriptionError(
|
|
8380
|
-
body.error ?? `cancel failed (${res.status})`,
|
|
8381
|
-
res.status
|
|
8382
|
-
);
|
|
8514
|
+
throw new CancelSubscriptionError(body.error ?? `cancel failed (${res.status})`, res.status);
|
|
8383
8515
|
}
|
|
8384
8516
|
return await res.json();
|
|
8385
8517
|
}
|
|
@@ -8555,6 +8687,8 @@ export {
|
|
|
8555
8687
|
meterAi,
|
|
8556
8688
|
meterUsage,
|
|
8557
8689
|
meterVectorize,
|
|
8690
|
+
mintAppId,
|
|
8691
|
+
mintUlid,
|
|
8558
8692
|
noopPermissionContext,
|
|
8559
8693
|
parseQuotaLimit,
|
|
8560
8694
|
platformCorsPatterns,
|