deepspace 0.15.0 → 0.16.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 +16 -0
- package/dist/cli.js +7 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +25 -18
- package/dist/server.js +35 -14
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +40 -18
- package/dist/worker.js +36 -14
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/server.d.ts
CHANGED
|
@@ -219,28 +219,24 @@ declare const UPLOAD_PART_BYTES: number;
|
|
|
219
219
|
*/
|
|
220
220
|
declare const MAX_UPLOAD_PARTS: number;
|
|
221
221
|
/**
|
|
222
|
-
*
|
|
223
|
-
*
|
|
222
|
+
* The customer-visible storage schedule, in bytes, PER ACCOUNT — the total an
|
|
223
|
+
* owner's uploaded files may occupy across every app they own, not a budget
|
|
224
|
+
* each app gets separately. This is the number the billing page advertises.
|
|
224
225
|
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* - the app-files allocation, admitted by the shared files handler
|
|
228
|
-
* (`server/utils/scoped-r2-files.ts`)
|
|
226
|
+
* Admitted by the shared files handler (`server/utils/scoped-r2-files.ts`),
|
|
227
|
+
* which sums the owner's apps rather than the one being written to.
|
|
229
228
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* customer-visible "storage" number is the app-files allocation — the repo
|
|
233
|
-
* store is platform bookkeeping that degrades (drops rollback retention)
|
|
234
|
-
* rather than surfacing here.
|
|
229
|
+
* It deliberately does NOT govern the repo store — see
|
|
230
|
+
* `REPO_STORE_LIMIT_BYTES` below, and docs/platform/r2-storage.md.
|
|
235
231
|
*/
|
|
236
|
-
declare const
|
|
232
|
+
declare const ACCOUNT_STORAGE_LIMIT_BYTES: {
|
|
237
233
|
readonly test: 0;
|
|
238
234
|
readonly free: number;
|
|
239
235
|
readonly starter: number;
|
|
240
236
|
readonly premium: number;
|
|
241
237
|
readonly admin: number;
|
|
242
238
|
};
|
|
243
|
-
/** The storage limit for a billing tier; unknown or missing tiers get free. */
|
|
239
|
+
/** The account storage limit for a billing tier; unknown or missing tiers get free. */
|
|
244
240
|
declare function storageLimitForTier(tier: string | null | undefined): number;
|
|
245
241
|
/** The one storage-quota refusal sentence. `usedBytes` is net of any object
|
|
246
242
|
* the upload replaces, so an upsert is charged only for its growth. */
|
|
@@ -323,15 +319,26 @@ interface ScopedR2Config {
|
|
|
323
319
|
* applies.
|
|
324
320
|
*/
|
|
325
321
|
interface StorageAdmission {
|
|
326
|
-
/**
|
|
327
|
-
* (possibly deeper) scope prefix a request resolved to. */
|
|
322
|
+
/** This app's own prefix — the one the incoming write lands under. */
|
|
328
323
|
prefix: string;
|
|
329
324
|
/**
|
|
330
325
|
* Resolve the owner's limit in bytes. `null` means the lookup failed;
|
|
331
|
-
* writes then fail closed (503) rather than admitting unmetered storage
|
|
332
|
-
* mirroring the repo store's `StorageBillingUnavailableError`.
|
|
326
|
+
* writes then fail closed (503) rather than admitting unmetered storage.
|
|
333
327
|
*/
|
|
334
328
|
limitBytes: () => Promise<number | null>;
|
|
329
|
+
/**
|
|
330
|
+
* The OTHER app prefixes this owner's storage spans, if any.
|
|
331
|
+
*
|
|
332
|
+
* The limit is per ACCOUNT, not per app: an owner's allocation is the total
|
|
333
|
+
* across everything they own, so admission has to see the siblings too. `[]`
|
|
334
|
+
* for an owner with one app, which is the common case and costs exactly what
|
|
335
|
+
* it did when this was a per-app limit.
|
|
336
|
+
*
|
|
337
|
+
* Returning `null` means the owner's apps could not be enumerated. Like a
|
|
338
|
+
* failed limit lookup that fails the write closed rather than admitting a
|
|
339
|
+
* write against an allocation we cannot measure.
|
|
340
|
+
*/
|
|
341
|
+
siblingPrefixes?: () => Promise<string[] | null>;
|
|
335
342
|
}
|
|
336
343
|
interface ScopedR2Auth {
|
|
337
344
|
userId: string | null;
|
|
@@ -4659,4 +4666,4 @@ declare class RefundError extends Error {
|
|
|
4659
4666
|
constructor(message: string, status: number);
|
|
4660
4667
|
}
|
|
4661
4668
|
|
|
4662
|
-
export { AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES,
|
|
4669
|
+
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 GameInput, GameRoom, type GameRoomConfig, 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 Player, 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, 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, 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
|
@@ -180,19 +180,21 @@ var MAX_UPLOAD_REQUEST_BYTES = 25 * 1024 * 1024;
|
|
|
180
180
|
var UPLOAD_PART_BYTES = 20 * 1024 * 1024;
|
|
181
181
|
var MAX_UPLOAD_PARTS = Math.ceil(MAX_APP_FILE_BYTES / UPLOAD_PART_BYTES);
|
|
182
182
|
var MAX_BASE64_UPLOAD_BYTES = Math.floor(MAX_UPLOAD_REQUEST_BYTES * 3 / 4);
|
|
183
|
-
var
|
|
183
|
+
var GIB = 1024 * 1024 * 1024;
|
|
184
|
+
var ACCOUNT_STORAGE_LIMIT_BYTES = {
|
|
184
185
|
test: 0,
|
|
185
|
-
free:
|
|
186
|
-
starter:
|
|
187
|
-
premium:
|
|
188
|
-
admin:
|
|
186
|
+
free: 1 * GIB,
|
|
187
|
+
starter: 10 * GIB,
|
|
188
|
+
premium: 30 * GIB,
|
|
189
|
+
admin: 100 * GIB
|
|
189
190
|
};
|
|
190
191
|
function storageLimitForTier(tier) {
|
|
191
|
-
if (tier && Object.hasOwn(
|
|
192
|
-
return
|
|
192
|
+
if (tier && Object.hasOwn(ACCOUNT_STORAGE_LIMIT_BYTES, tier)) {
|
|
193
|
+
return ACCOUNT_STORAGE_LIMIT_BYTES[tier];
|
|
193
194
|
}
|
|
194
|
-
return
|
|
195
|
+
return ACCOUNT_STORAGE_LIMIT_BYTES.free;
|
|
195
196
|
}
|
|
197
|
+
var REPO_STORE_LIMIT_BYTES = 256 * 1024 * 1024;
|
|
196
198
|
function storageQuotaMessage(incomingBytes, usedBytes, limitBytes) {
|
|
197
199
|
const free = Math.max(0, limitBytes - usedBytes);
|
|
198
200
|
return `This upload needs ${formatBytes(incomingBytes)} but the app's file storage has ${formatBytes(free)} free (${formatBytes(usedBytes)} of ${formatBytes(limitBytes)} used). Delete files with \`deepspace app files rm <key>\`, or upgrade the owner's plan.`;
|
|
@@ -283,7 +285,7 @@ function declaredLength(request, what) {
|
|
|
283
285
|
function isKeyWithinPrefix(key, prefix) {
|
|
284
286
|
return key.startsWith(prefix);
|
|
285
287
|
}
|
|
286
|
-
async function
|
|
288
|
+
async function prefixUsage(bucket, prefix) {
|
|
287
289
|
let total = 0;
|
|
288
290
|
let cursor;
|
|
289
291
|
do {
|
|
@@ -293,6 +295,13 @@ async function allocationUsage(bucket, prefix) {
|
|
|
293
295
|
} while (cursor !== void 0);
|
|
294
296
|
return total;
|
|
295
297
|
}
|
|
298
|
+
async function allocationUsage(bucket, storage) {
|
|
299
|
+
const siblings = storage.siblingPrefixes ? await storage.siblingPrefixes() : [];
|
|
300
|
+
if (siblings === null) return null;
|
|
301
|
+
const prefixes = [storage.prefix, ...siblings.filter((p) => p !== storage.prefix)];
|
|
302
|
+
const totals = await Promise.all(prefixes.map((prefix) => prefixUsage(bucket, prefix)));
|
|
303
|
+
return totals.reduce((sum, bytes) => sum + bytes, 0);
|
|
304
|
+
}
|
|
296
305
|
async function admitStorage(bucket, storage, incomingBytes, replacesKey) {
|
|
297
306
|
if (!storage) return null;
|
|
298
307
|
const limit = await storage.limitBytes();
|
|
@@ -303,7 +312,14 @@ async function admitStorage(bucket, storage, incomingBytes, replacesKey) {
|
|
|
303
312
|
"storage_limit_unavailable"
|
|
304
313
|
);
|
|
305
314
|
}
|
|
306
|
-
const stored = await allocationUsage(bucket, storage
|
|
315
|
+
const stored = await allocationUsage(bucket, storage);
|
|
316
|
+
if (stored === null) {
|
|
317
|
+
return fail(
|
|
318
|
+
503,
|
|
319
|
+
"The storage already used by this account could not be measured; nothing was uploaded. Retry shortly.",
|
|
320
|
+
"storage_limit_unavailable"
|
|
321
|
+
);
|
|
322
|
+
}
|
|
307
323
|
const replaced = replacesKey === null ? 0 : (await bucket.head(replacesKey))?.size ?? 0;
|
|
308
324
|
const used = stored - replaced;
|
|
309
325
|
if (used + incomingBytes <= limit) return null;
|
|
@@ -319,7 +335,11 @@ async function admitAssembledObject(bucket, storage, key, objectBytes) {
|
|
|
319
335
|
console.error("[files:quota] limit unavailable at complete; keeping", key);
|
|
320
336
|
return null;
|
|
321
337
|
}
|
|
322
|
-
const stored = await allocationUsage(bucket, storage
|
|
338
|
+
const stored = await allocationUsage(bucket, storage);
|
|
339
|
+
if (stored === null) {
|
|
340
|
+
console.error("[files:quota] account usage unmeasurable at complete; keeping", key);
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
323
343
|
if (stored <= limit) return null;
|
|
324
344
|
await bucket.delete(key).catch(() => void 0);
|
|
325
345
|
return fail(
|
|
@@ -716,9 +736,10 @@ async function handleList(bucket, prefix, url, scope, auth) {
|
|
|
716
736
|
});
|
|
717
737
|
let storage;
|
|
718
738
|
if (auth.storage) {
|
|
719
|
-
|
|
739
|
+
const usedBytes = await allocationUsage(bucket, auth.storage);
|
|
740
|
+
if (usedBytes !== null) storage = { usedBytes };
|
|
720
741
|
const limitBytes = await auth.storage.limitBytes();
|
|
721
|
-
if (limitBytes !== null) storage.limitBytes = limitBytes;
|
|
742
|
+
if (storage && limitBytes !== null) storage.limitBytes = limitBytes;
|
|
722
743
|
}
|
|
723
744
|
return Response.json(
|
|
724
745
|
{ files, truncated: listed.truncated, ...storage ? { storage } : {} },
|
|
@@ -7984,12 +8005,12 @@ var RefundError = class extends Error {
|
|
|
7984
8005
|
}
|
|
7985
8006
|
};
|
|
7986
8007
|
export {
|
|
8008
|
+
ACCOUNT_STORAGE_LIMIT_BYTES,
|
|
7987
8009
|
AI_CHATS_SCHEMA,
|
|
7988
8010
|
AI_MESSAGES_SCHEMA,
|
|
7989
8011
|
ALLOWED_BINDING_TYPES,
|
|
7990
8012
|
APP_ID_RE,
|
|
7991
8013
|
APP_NAME_RULES,
|
|
7992
|
-
APP_STORAGE_LIMIT_BYTES,
|
|
7993
8014
|
AUTO_PROVISIONABLE_TYPES,
|
|
7994
8015
|
AUTO_PROVISION_SENTINEL,
|
|
7995
8016
|
BASE_USERS_SCHEMA,
|