@sprigr/apps-app-sdk 0.21.1 → 0.23.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/README.md +1 -0
- package/dist/index.d.ts +160 -1
- package/dist/index.js +179 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,6 +95,7 @@ Three platform tiers, and they are not substitutes for each other. Full guide: [
|
|
|
95
95
|
|
|
96
96
|
- `requireApproval(handlers, specs, opts)` wraps the named tools so each returns an `_approval` card instead of writing, then on the granted pass captures a before-image through the **pinned** connection and offers `_undo`. It resolves the connection inside itself, before the label lookup, the hash and the capture: a gate that sits outside the app's own pin names the wrong store, hashes the wrong store and captures the wrong store's copy. Register the result after the originals: `Object.assign(registry, requireApproval(registry, SPECS, opts))`.
|
|
97
97
|
- `dispatcherApproval(specs, opts)`: the same gate for a one-tool-many-actions dispatcher. Build it beside the action registry and call `gate.run(action, args, env, () => def.execute(state, parsed))` from the dispatcher; params are read from `opts.inputField` (default `input`), the action name is hashed in, and `pinEnv` may return a per-actor token state rather than the env.
|
|
98
|
+
- A spec with no `hash` binds the grant to its payload: every argument except the `keys` fields, the attestation flags and the gate's `connectionArgs` (e.g. `['store']`) goes into the hash canonically, so a tap on one payload cannot be spent on another (sprigr-apps#2605). See docs/write-protection.md.
|
|
98
99
|
- Every resolver on the gate is a **default, overridable per spec**: `ApprovalSpec.resolveConnection`, `.describeTarget` and `.stampConnection` win over the gate's for that spec alone. Reach for it when one app has two families of write that reach a connection differently (creates that POST under an account, deletes that address a global object id on a path carrying no account). One gate-level rule has to pick one of them, and for the other it prints a false connection on the card a person taps and mixes it into the grant hash. A spec that hits no connection returns `''`.
|
|
99
100
|
- `approvalHash(rawId, connection, ...parts)`, `set(values)`, `seq(values)`: a stable operation identity so a tap survives the model reordering a list or dropping an optional argument on the retry.
|
|
100
101
|
- `undoEnvelope({...})` throws on a blank field. The platform drops the whole envelope on a blank and mints nothing, silently.
|
package/dist/index.d.ts
CHANGED
|
@@ -1890,6 +1890,14 @@ interface ApprovalSpec<P = unknown, E = unknown> {
|
|
|
1890
1890
|
/**
|
|
1891
1891
|
* Extra identity parts beyond `rawId + connection`, e.g. a sorted tag set.
|
|
1892
1892
|
* Use `set()` / `seq()` from `approval-hash`. Never include `confirm`.
|
|
1893
|
+
*
|
|
1894
|
+
* Omitted, the wrapper appends a canonical form of every OTHER argument:
|
|
1895
|
+
* not the `keys` fields, not `confirm` / `_approval_granted`, and not the
|
|
1896
|
+
* gate's `connectionArgs` (sprigr-apps#2605). So a grant approved for one
|
|
1897
|
+
* payload cannot be spent on another; before, a hash-less refund hashed the
|
|
1898
|
+
* same for 10.00 and 250.00. Supply `hash` when that default is too strict
|
|
1899
|
+
* (an order-insensitive set, a free-text field the model rewords) or
|
|
1900
|
+
* `() => []` when the id and connection really are the whole operation.
|
|
1893
1901
|
*/
|
|
1894
1902
|
hash?: (args: ToolArgs) => Array<string | number | undefined | null>;
|
|
1895
1903
|
/**
|
|
@@ -1972,6 +1980,14 @@ interface ApprovalGateOptions<E, P = E> {
|
|
|
1972
1980
|
* `ApprovalSpec.resolveConnection`.
|
|
1973
1981
|
*/
|
|
1974
1982
|
resolveConnection: (env: E, args: ToolArgs) => Promise<string>;
|
|
1983
|
+
/**
|
|
1984
|
+
* Argument names that only CHOOSE the connection (e.g. `['store']`). They
|
|
1985
|
+
* are left out of the default payload hash (see `ApprovalSpec.hash`)
|
|
1986
|
+
* because the connection is already in the hash in its RESOLVED form, and
|
|
1987
|
+
* the model usually omits the raw argument on the retry. Omit for a
|
|
1988
|
+
* single-connection app.
|
|
1989
|
+
*/
|
|
1990
|
+
connectionArgs?: string[];
|
|
1975
1991
|
/**
|
|
1976
1992
|
* Re-pin to a resolved connection so lookups and captures hit it. Omit when
|
|
1977
1993
|
* `P` is `E` and the env needs no pin (a single-connection app).
|
|
@@ -2778,6 +2794,136 @@ declare function callerKeyRefusal(key: string, r: Extract<CallerKeyResolution, {
|
|
|
2778
2794
|
ok: false;
|
|
2779
2795
|
}>): string;
|
|
2780
2796
|
|
|
2797
|
+
/**
|
|
2798
|
+
* Removing mirrored rows from an app's data index, from either execution
|
|
2799
|
+
* context (sprigr/sprigr-app-kit#123).
|
|
2800
|
+
*
|
|
2801
|
+
* An app that mirrors an account into its search index must drop that
|
|
2802
|
+
* account's rows when the install switches to another account or
|
|
2803
|
+
* disconnects; otherwise the next user searches the previous account's data
|
|
2804
|
+
* (sprigr/sprigr-apps#2900). Five apps each wrote the same pieces: a data
|
|
2805
|
+
* client that uses `env.SPRIGR.data` on a dispatched handler and the
|
|
2806
|
+
* install-token routes on an inline route, a prefix listing, and a chunked
|
|
2807
|
+
* delete that reports rather than throws. This module is the one copy.
|
|
2808
|
+
*
|
|
2809
|
+
* The pattern it serves, "snapshot, then purge exactly that":
|
|
2810
|
+
*
|
|
2811
|
+
* const before = await snapshotIndexIds(env, [{ prefix: 'trello:card:', index: 'cards' }]);
|
|
2812
|
+
* await storeNewAccountTokens(...); // the switch
|
|
2813
|
+
* const res = await deleteSnapshotIds(env, before);
|
|
2814
|
+
*
|
|
2815
|
+
* Rows written after the snapshot (the new account's first sync, a late
|
|
2816
|
+
* webhook) are not in it and survive. `purgeIndexByPrefix` is the one-step
|
|
2817
|
+
* form for a disconnect, where nothing new is being written.
|
|
2818
|
+
*
|
|
2819
|
+
* Neither purge function throws. A purge runs inside a connect or disconnect
|
|
2820
|
+
* flow that must finish; the result carries `error` and `truncated` so the
|
|
2821
|
+
* caller can audit an incomplete purge instead of losing it in a catch.
|
|
2822
|
+
*
|
|
2823
|
+
* Wire contract (workers/provisioning/src/wfp-data.ts in sprigr-team):
|
|
2824
|
+
* POST /internal/wfp/data/list-ids { prefix, index?, withAcl? }
|
|
2825
|
+
* 200 { objectIDs, total, truncated } (prefix must be non-empty; cap 50000)
|
|
2826
|
+
* POST /internal/wfp/data/delete { objectIDs, index?, withAcl? }
|
|
2827
|
+
* 200 { ok, deleted, index } (max 1000 ids; unknown ids are no-ops)
|
|
2828
|
+
*/
|
|
2829
|
+
|
|
2830
|
+
/** Options for the id routes: a logical index, and the app's ACL index. */
|
|
2831
|
+
interface DataIdsOpts extends SprigrDataIndexOpts {
|
|
2832
|
+
withAcl?: boolean;
|
|
2833
|
+
}
|
|
2834
|
+
interface DataListIdsResult {
|
|
2835
|
+
objectIDs: string[];
|
|
2836
|
+
total: number;
|
|
2837
|
+
/** The platform returned its cap's worth and stopped: more rows exist. */
|
|
2838
|
+
truncated: boolean;
|
|
2839
|
+
}
|
|
2840
|
+
/** How a data call reaches the platform. `none` means it cannot. */
|
|
2841
|
+
type DataTransport = 'binding' | 'http' | 'none';
|
|
2842
|
+
/** The data surface with every member present, whichever transport carries it. */
|
|
2843
|
+
interface DataClient {
|
|
2844
|
+
via: Exclude<DataTransport, 'none'>;
|
|
2845
|
+
import(objects: Array<{
|
|
2846
|
+
objectID: string;
|
|
2847
|
+
[key: string]: unknown;
|
|
2848
|
+
}>, opts?: SprigrDataImportOpts): Promise<{
|
|
2849
|
+
ok: boolean;
|
|
2850
|
+
indexed: number;
|
|
2851
|
+
index: string;
|
|
2852
|
+
}>;
|
|
2853
|
+
search(opts?: SprigrDataSearchOpts): Promise<SprigrDataSearchResult>;
|
|
2854
|
+
get(objectID: string, opts?: SprigrDataIndexOpts): Promise<{
|
|
2855
|
+
ok: boolean;
|
|
2856
|
+
object: Record<string, unknown> | null;
|
|
2857
|
+
index: string;
|
|
2858
|
+
}>;
|
|
2859
|
+
partialUpdate(objects: Array<{
|
|
2860
|
+
objectID: string;
|
|
2861
|
+
[key: string]: unknown;
|
|
2862
|
+
}>, opts?: SprigrDataPartialUpdateOpts): Promise<SprigrDataPartialUpdateResult>;
|
|
2863
|
+
delete(objectIDs: string[], opts?: DataIdsOpts): Promise<{
|
|
2864
|
+
ok: boolean;
|
|
2865
|
+
deleted: number;
|
|
2866
|
+
index: string;
|
|
2867
|
+
}>;
|
|
2868
|
+
listIds(prefix: string, opts?: DataIdsOpts): Promise<DataListIdsResult>;
|
|
2869
|
+
}
|
|
2870
|
+
/** Max ids one delete call takes (the platform's per-call cap). */
|
|
2871
|
+
declare const DATA_DELETE_MAX_IDS = 1000;
|
|
2872
|
+
/**
|
|
2873
|
+
* The app's data surface on either transport, or null when neither exists.
|
|
2874
|
+
*
|
|
2875
|
+
* Uses `env.SPRIGR.data` when it carries BOTH `listIds` and `delete` (a
|
|
2876
|
+
* dispatched handler on a current wrapper build); otherwise the install-token
|
|
2877
|
+
* routes, which an inline Next route can reach and an older wrapper build
|
|
2878
|
+
* lacks members for. Every member then exists, so callers never feature-detect.
|
|
2879
|
+
*/
|
|
2880
|
+
declare function makeDataClient(env: WfpBridgeEnv): DataClient | null;
|
|
2881
|
+
/** One prefix to list, in one index. A bare string is a prefix in the default index. */
|
|
2882
|
+
type IdPrefixSpec = string | ({
|
|
2883
|
+
prefix: string;
|
|
2884
|
+
} & DataIdsOpts);
|
|
2885
|
+
/** The ids an index held at one moment, grouped by the index they live in. */
|
|
2886
|
+
interface IdSnapshot {
|
|
2887
|
+
groups: Array<{
|
|
2888
|
+
index?: string;
|
|
2889
|
+
withAcl?: boolean;
|
|
2890
|
+
ids: string[];
|
|
2891
|
+
}>;
|
|
2892
|
+
/** Distinct ids across every group. */
|
|
2893
|
+
listed: number;
|
|
2894
|
+
/** A listing hit the platform's cap: the snapshot misses some rows. */
|
|
2895
|
+
truncated: boolean;
|
|
2896
|
+
via: DataTransport;
|
|
2897
|
+
/** Set when a listing failed; the groups hold whatever was listed before it. */
|
|
2898
|
+
error?: string;
|
|
2899
|
+
}
|
|
2900
|
+
interface PurgeResult {
|
|
2901
|
+
deleted: number;
|
|
2902
|
+
listed: number;
|
|
2903
|
+
truncated: boolean;
|
|
2904
|
+
via: DataTransport;
|
|
2905
|
+
/** Set when the purge stopped early. `deleted` says how far it got. */
|
|
2906
|
+
error?: string;
|
|
2907
|
+
}
|
|
2908
|
+
/**
|
|
2909
|
+
* Every id matching the prefixes right now. Never throws. With no data path
|
|
2910
|
+
* at all the app cannot have written rows, so the snapshot is empty with
|
|
2911
|
+
* `via: 'none'` and no error.
|
|
2912
|
+
*/
|
|
2913
|
+
declare function snapshotIndexIds(env: WfpBridgeEnv, prefixes: readonly IdPrefixSpec[]): Promise<IdSnapshot>;
|
|
2914
|
+
/**
|
|
2915
|
+
* Delete exactly the ids in a snapshot, in chunks of `chunk` (default and
|
|
2916
|
+
* ceiling 1000). Never throws. A snapshot that carries a listing error is
|
|
2917
|
+
* still purged as far as it goes, and the error is passed on.
|
|
2918
|
+
*/
|
|
2919
|
+
declare function deleteSnapshotIds(env: WfpBridgeEnv, snapshot: IdSnapshot, opts?: {
|
|
2920
|
+
chunk?: number;
|
|
2921
|
+
}): Promise<PurgeResult>;
|
|
2922
|
+
/** List, then delete, everything matching the prefixes. Never throws. */
|
|
2923
|
+
declare function purgeIndexByPrefix(env: WfpBridgeEnv, prefixes: readonly IdPrefixSpec[], opts?: {
|
|
2924
|
+
chunk?: number;
|
|
2925
|
+
}): Promise<PurgeResult>;
|
|
2926
|
+
|
|
2781
2927
|
/**
|
|
2782
2928
|
* @sprigr/apps-app-sdk
|
|
2783
2929
|
*
|
|
@@ -3092,6 +3238,19 @@ interface SprigrDataApi {
|
|
|
3092
3238
|
deleted: number;
|
|
3093
3239
|
index: string;
|
|
3094
3240
|
}>;
|
|
3241
|
+
/**
|
|
3242
|
+
* List the objectIDs that start with `prefix` (non-empty, so a listing is
|
|
3243
|
+
* always scoped). Returns at most 50000 with `truncated: true` past that.
|
|
3244
|
+
* `?`-optional for older wrapper builds; `makeDataClient` and
|
|
3245
|
+
* `purgeIndexByPrefix` fall back to the install-token route.
|
|
3246
|
+
*/
|
|
3247
|
+
listIds?(prefix: string, opts?: SprigrDataIndexOpts & {
|
|
3248
|
+
withAcl?: boolean;
|
|
3249
|
+
}): Promise<{
|
|
3250
|
+
objectIDs: string[];
|
|
3251
|
+
total?: number;
|
|
3252
|
+
truncated: boolean;
|
|
3253
|
+
}>;
|
|
3095
3254
|
}
|
|
3096
3255
|
/**
|
|
3097
3256
|
* Durable app file storage exposed on `env.SPRIGR.files` by the platform
|
|
@@ -3339,4 +3498,4 @@ interface ExecutionContextLike {
|
|
|
3339
3498
|
}
|
|
3340
3499
|
type HandlerFn<TArgs, TResult> = (args: TArgs, env: Record<string, unknown>, ctx?: ExecutionContextLike) => Promise<TResult>;
|
|
3341
3500
|
|
|
3342
|
-
export { ACTOR_RETIRED_HOOK_TOOL, ACTOR_RETIRE_REASONS, APPROVAL_GRANTED_KEY, APPROVAL_PREVIEW_MAX, APP_FILES_ROOT, APP_OWNER_SEGMENT, type Actor, type ActorRetireReason, type ActorRetired, type ActorRetiredHookBody, type ActorRetiredResult, type AppApprovalEnvelope, type AppFileListItem, type AppFileUrlArgs, type AppFileUrlResult, type AppFilesEnv, type AppToolEffectsDeclaration, type AppUndoEnvelope, type ApplyPoliciesOptions, type ApprovalCoverage, type ApprovalGateOptions, type ApprovalSpec, type ArchiveOfferOptions, type ArchiveOfferRefusal, type CallerKeyResolution, type CaptureJournal, type ConfirmCondition, type ConfirmRule, type ConfirmationPolicy, type ConnectCompleteRequest, type ConnectCompleteResult, type D1Like, type D1PreparedStatementLike, DATA_PARTIAL_UPDATE_PATH, DEFAULT_EMIT_TIMEOUT_MS, DEFAULT_FILE_READ_TIMEOUT_MS, DEFAULT_LOG_TIMEOUT_MS, DEFAULT_MAX_FILE_BYTES, DEFAULT_MONEY_FIELDS, DEFAULT_WRITE_PREFIXES, type DerivePolicyOptions, type DerivedPolicy, type DispatcherApprovalGate, type DispatcherApprovalOptions, type EmitMarketplaceEventOptions, type EmitResult, type EmitTransport, type EventArgs, type ExecutionContextLike, FILE_REF_SOURCES_HELP, type FetchFileResult, type FetchWithRetryOptions, type FileRef, type FileRefContent, type FileRefEnv, FileRefError, type FileRefErrorCode, type FileRefStream, type FileRefVia, type GetAppFileResult, type HandlerFn, INBOX_SEND_CONTRACT_V1, type InboxAddress, type InboxAppendRequest, type InboxAppendResult, type InboxChannelDeclaration, type InboxFoldersRequest, type InboxFoldersResult, type InboxOwner, type InboxSendConnection, type InboxSendHandlerImpl, InboxSendRefusal, type InboxSendSupports, type InboxSendV1Args, type InboxSendV1Result, type InstallBridge, InvalidUndoEnvelopeError, type JournalRowLike, type LogToPlatformOptions, type ManifestDispatchBlock, type ManifestLike, type ManifestToolLike, type MarketplaceEventEmitOpts, type MarketplaceEventSourceIntegration, NotConnectedError, type OAuthBouncerSignals, type OAuthState, type OfferUndoArgs, type PartialUpdateDataOptions, type PlatformHostEnv, type PolicyCheckInput, type PolicySource, type PutAppFileArgs, type PutAppFileResult, type PutAppFileStreamArgs, type ReadFileRefOptions, type RequireApprovalOptions, type ResolveFileRefOptions, type ResolveViewerOptions, type ResolvedFileRef, type RestoreResult, type RestoreSpec, SPRIGR_DATA_MAX_OBJECTS_PER_CALL, SPRIGR_FILE_HOSTS, SPRIGR_LOG_LEVELS, SPRIGR_LOG_LIMITS, type ScheduleArgs, type SprigrDataAggregationCell, type SprigrDataAggregationResult, type SprigrDataAggregationSpec, type SprigrDataApi, type SprigrDataImportOpts, type SprigrDataIndexOpts, type SprigrDataPartialUpdateBody, type SprigrDataPartialUpdateOpts, type SprigrDataPartialUpdateResult, type SprigrDataPatch, type SprigrDataSearchOpts, type SprigrDataSearchResult, SprigrDataValidationError, type SprigrFilesApi, type SprigrFilesApiWithEdit, type SprigrFilesCreateInput, type SprigrFilesCreateResult, type SprigrFilesEditInput, type SprigrFilesEditResult, type SprigrFilesJobResult, type SprigrFilesListItem, type SprigrFilesListResult, type SprigrInboxApi, type SprigrLogEntry, type SprigrLogFn, type SprigrLogLevel, type SprigrLogResult, SprigrLogValidationError, type SyncedAttachment, type SyncedMessage, type ToolArgs, type ToolHandler, type ToolResult, type ToolWrapperOptions, UNIT_SEP, type UndoApplyOptions, type UndoApplyResult, type UndoCaptureSpec, type UndoFidelity, VIEWER_ANONYMOUS, VIEWER_CONTEXT_HEADER, VIEWER_PLATFORM_USER_ID_HEADER, VIEWER_ROLE_HEADER, VIEWER_USER_ID_HEADER, type VerbRule, type ViewerContext, type ViewerContextFailure, type ViewerContextVerification, type ViewerEnv, WORKSPACE_FILE_HOW_TO, type WebhookArgs, type WfpBridgeEnv, type WfpEmitReply, actorKey, actorRetiredHook, actorTool, agentFileKeyFromUrl, appFileUrl, appKeyFromCallerKey, applyConfirmationPolicies, approvalHash, approvalPreview, approvalRecipients, archiveOfferRefusal, attendedFindings, base64ToBytes, buildConfirmationPolicy, buildMarketplaceWebhookUrl, buildPartialUpdateBody, bytesToBase64, callerKeyRefusal, canEmit, canLog, canPartialUpdate, checkConfirmationPolicy, commonDestructiveVerbs, connectComplete, connectDisconnect, constantTimeEqual, createMarketplaceEmitter, createToolWrappers, decodeState, defineInboxSendHandler, deleteAppFile, deriveConfirmationPolicy, describeMissingBridge, dispatcherApproval, emitMarketplaceEvent, encodeState, fetchFileAsBase64, fetchFileBytes, fetchWithRetry, fullWarning, getAppFile, hmacSha256Hex, installTokenPost, isNotConnectedError, isStagingHost, listAppFiles, logToPlatform, manifestIsFresh, offerUndo, openFileRef, overlaySprigr, ownerFromActorKey, parseActor, parseActorRetiredArgs, partialUpdateData, putAppFile, putAppFileStream, randomHex, readFileRef, readableStoredKey, recreatedWarning, refuseWithoutForce, requireApproval, resolveFileRef, resolveInstallBridge, resolveOAuthBouncerBase, resolveOAuthBouncerCallbackUrl, resolvePlatformWebhookBase, resolveViewerContext, resolveViewerUserId, runUndoApply, safeCapture, seq, serializeManifest, set, tool, undoEnvelope, validateLogEntries, validateLogEntry, verifyViewerToken, withSprigrEmitFallback, withSprigrInboxFallback, withSprigrLogFallback };
|
|
3501
|
+
export { ACTOR_RETIRED_HOOK_TOOL, ACTOR_RETIRE_REASONS, APPROVAL_GRANTED_KEY, APPROVAL_PREVIEW_MAX, APP_FILES_ROOT, APP_OWNER_SEGMENT, type Actor, type ActorRetireReason, type ActorRetired, type ActorRetiredHookBody, type ActorRetiredResult, type AppApprovalEnvelope, type AppFileListItem, type AppFileUrlArgs, type AppFileUrlResult, type AppFilesEnv, type AppToolEffectsDeclaration, type AppUndoEnvelope, type ApplyPoliciesOptions, type ApprovalCoverage, type ApprovalGateOptions, type ApprovalSpec, type ArchiveOfferOptions, type ArchiveOfferRefusal, type CallerKeyResolution, type CaptureJournal, type ConfirmCondition, type ConfirmRule, type ConfirmationPolicy, type ConnectCompleteRequest, type ConnectCompleteResult, type D1Like, type D1PreparedStatementLike, DATA_DELETE_MAX_IDS, DATA_PARTIAL_UPDATE_PATH, DEFAULT_EMIT_TIMEOUT_MS, DEFAULT_FILE_READ_TIMEOUT_MS, DEFAULT_LOG_TIMEOUT_MS, DEFAULT_MAX_FILE_BYTES, DEFAULT_MONEY_FIELDS, DEFAULT_WRITE_PREFIXES, type DataClient, type DataIdsOpts, type DataListIdsResult, type DataTransport, type DerivePolicyOptions, type DerivedPolicy, type DispatcherApprovalGate, type DispatcherApprovalOptions, type EmitMarketplaceEventOptions, type EmitResult, type EmitTransport, type EventArgs, type ExecutionContextLike, FILE_REF_SOURCES_HELP, type FetchFileResult, type FetchWithRetryOptions, type FileRef, type FileRefContent, type FileRefEnv, FileRefError, type FileRefErrorCode, type FileRefStream, type FileRefVia, type GetAppFileResult, type HandlerFn, INBOX_SEND_CONTRACT_V1, type IdPrefixSpec, type IdSnapshot, type InboxAddress, type InboxAppendRequest, type InboxAppendResult, type InboxChannelDeclaration, type InboxFoldersRequest, type InboxFoldersResult, type InboxOwner, type InboxSendConnection, type InboxSendHandlerImpl, InboxSendRefusal, type InboxSendSupports, type InboxSendV1Args, type InboxSendV1Result, type InstallBridge, InvalidUndoEnvelopeError, type JournalRowLike, type LogToPlatformOptions, type ManifestDispatchBlock, type ManifestLike, type ManifestToolLike, type MarketplaceEventEmitOpts, type MarketplaceEventSourceIntegration, NotConnectedError, type OAuthBouncerSignals, type OAuthState, type OfferUndoArgs, type PartialUpdateDataOptions, type PlatformHostEnv, type PolicyCheckInput, type PolicySource, type PurgeResult, type PutAppFileArgs, type PutAppFileResult, type PutAppFileStreamArgs, type ReadFileRefOptions, type RequireApprovalOptions, type ResolveFileRefOptions, type ResolveViewerOptions, type ResolvedFileRef, type RestoreResult, type RestoreSpec, SPRIGR_DATA_MAX_OBJECTS_PER_CALL, SPRIGR_FILE_HOSTS, SPRIGR_LOG_LEVELS, SPRIGR_LOG_LIMITS, type ScheduleArgs, type SprigrDataAggregationCell, type SprigrDataAggregationResult, type SprigrDataAggregationSpec, type SprigrDataApi, type SprigrDataImportOpts, type SprigrDataIndexOpts, type SprigrDataPartialUpdateBody, type SprigrDataPartialUpdateOpts, type SprigrDataPartialUpdateResult, type SprigrDataPatch, type SprigrDataSearchOpts, type SprigrDataSearchResult, SprigrDataValidationError, type SprigrFilesApi, type SprigrFilesApiWithEdit, type SprigrFilesCreateInput, type SprigrFilesCreateResult, type SprigrFilesEditInput, type SprigrFilesEditResult, type SprigrFilesJobResult, type SprigrFilesListItem, type SprigrFilesListResult, type SprigrInboxApi, type SprigrLogEntry, type SprigrLogFn, type SprigrLogLevel, type SprigrLogResult, SprigrLogValidationError, type SyncedAttachment, type SyncedMessage, type ToolArgs, type ToolHandler, type ToolResult, type ToolWrapperOptions, UNIT_SEP, type UndoApplyOptions, type UndoApplyResult, type UndoCaptureSpec, type UndoFidelity, VIEWER_ANONYMOUS, VIEWER_CONTEXT_HEADER, VIEWER_PLATFORM_USER_ID_HEADER, VIEWER_ROLE_HEADER, VIEWER_USER_ID_HEADER, type VerbRule, type ViewerContext, type ViewerContextFailure, type ViewerContextVerification, type ViewerEnv, WORKSPACE_FILE_HOW_TO, type WebhookArgs, type WfpBridgeEnv, type WfpEmitReply, actorKey, actorRetiredHook, actorTool, agentFileKeyFromUrl, appFileUrl, appKeyFromCallerKey, applyConfirmationPolicies, approvalHash, approvalPreview, approvalRecipients, archiveOfferRefusal, attendedFindings, base64ToBytes, buildConfirmationPolicy, buildMarketplaceWebhookUrl, buildPartialUpdateBody, bytesToBase64, callerKeyRefusal, canEmit, canLog, canPartialUpdate, checkConfirmationPolicy, commonDestructiveVerbs, connectComplete, connectDisconnect, constantTimeEqual, createMarketplaceEmitter, createToolWrappers, decodeState, defineInboxSendHandler, deleteAppFile, deleteSnapshotIds, deriveConfirmationPolicy, describeMissingBridge, dispatcherApproval, emitMarketplaceEvent, encodeState, fetchFileAsBase64, fetchFileBytes, fetchWithRetry, fullWarning, getAppFile, hmacSha256Hex, installTokenPost, isNotConnectedError, isStagingHost, listAppFiles, logToPlatform, makeDataClient, manifestIsFresh, offerUndo, openFileRef, overlaySprigr, ownerFromActorKey, parseActor, parseActorRetiredArgs, partialUpdateData, purgeIndexByPrefix, putAppFile, putAppFileStream, randomHex, readFileRef, readableStoredKey, recreatedWarning, refuseWithoutForce, requireApproval, resolveFileRef, resolveInstallBridge, resolveOAuthBouncerBase, resolveOAuthBouncerCallbackUrl, resolvePlatformWebhookBase, resolveViewerContext, resolveViewerUserId, runUndoApply, safeCapture, seq, serializeManifest, set, snapshotIndexIds, tool, undoEnvelope, validateLogEntries, validateLogEntry, verifyViewerToken, withSprigrEmitFallback, withSprigrInboxFallback, withSprigrLogFallback };
|
package/dist/index.js
CHANGED
|
@@ -7,9 +7,9 @@ function constantTimeEqual(a, b) {
|
|
|
7
7
|
}
|
|
8
8
|
return mismatch === 0;
|
|
9
9
|
}
|
|
10
|
-
async function hmacSha256Hex(secret,
|
|
10
|
+
async function hmacSha256Hex(secret, message2) {
|
|
11
11
|
const keyData = new TextEncoder().encode(secret);
|
|
12
|
-
const msgData = new TextEncoder().encode(
|
|
12
|
+
const msgData = new TextEncoder().encode(message2);
|
|
13
13
|
const key = await crypto.subtle.importKey(
|
|
14
14
|
"raw",
|
|
15
15
|
keyData,
|
|
@@ -162,8 +162,8 @@ function platformBase(env) {
|
|
|
162
162
|
}
|
|
163
163
|
var AppFilesError = class extends Error {
|
|
164
164
|
status;
|
|
165
|
-
constructor(
|
|
166
|
-
super(
|
|
165
|
+
constructor(message2, status) {
|
|
166
|
+
super(message2);
|
|
167
167
|
this.name = "AppFilesError";
|
|
168
168
|
this.status = status;
|
|
169
169
|
}
|
|
@@ -210,10 +210,10 @@ function putAppFile(env, args) {
|
|
|
210
210
|
}
|
|
211
211
|
var STREAM_PUT_MAX_ATTEMPTS = 3;
|
|
212
212
|
var STREAM_PUT_BASE_DELAY_MS = 500;
|
|
213
|
-
function isTransientPutStreamFailure(status,
|
|
213
|
+
function isTransientPutStreamFailure(status, message2) {
|
|
214
214
|
if (status === 503) return true;
|
|
215
215
|
if (status !== 502) return false;
|
|
216
|
-
const msg =
|
|
216
|
+
const msg = message2.toLowerCase();
|
|
217
217
|
return msg.includes("(10001)") || msg.includes("(10043)");
|
|
218
218
|
}
|
|
219
219
|
function sleep2(ms) {
|
|
@@ -351,8 +351,8 @@ var WORKSPACE_FILE_HOW_TO = "Apps cannot open a file in your own Sprigr storage
|
|
|
351
351
|
var FILE_REF_SOURCES_HELP = "Pass exactly one of: file_key, a key this app's own tools returned; or file_url, an https Sprigr file link (on files.sprigr.com), either the download_url another app's tool returned or, for a file in your own Sprigr storage, a short-lived link from the files tool's generate_url.";
|
|
352
352
|
var FileRefError = class extends Error {
|
|
353
353
|
code;
|
|
354
|
-
constructor(code,
|
|
355
|
-
super(
|
|
354
|
+
constructor(code, message2) {
|
|
355
|
+
super(message2);
|
|
356
356
|
this.name = "FileRefError";
|
|
357
357
|
this.code = code;
|
|
358
358
|
}
|
|
@@ -444,11 +444,11 @@ async function openFileRef(env, ref, opts) {
|
|
|
444
444
|
const failure = (err) => {
|
|
445
445
|
if (err instanceof FileRefError) return err;
|
|
446
446
|
const name = err instanceof Error ? err.name : "";
|
|
447
|
-
const
|
|
447
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
448
448
|
if (name === "TimeoutError" || name === "AbortError") {
|
|
449
449
|
return new FileRefError("timeout", `Reading ${label} took longer than ${Math.round(timeoutMs / 1e3)}s, so it was not read.`);
|
|
450
450
|
}
|
|
451
|
-
return new FileRefError("read_failed", `Could not read ${label}: ${
|
|
451
|
+
return new FileRefError("read_failed", `Could not read ${label}: ${message2}`);
|
|
452
452
|
};
|
|
453
453
|
const openUrl = async (url, via, filename) => {
|
|
454
454
|
let res;
|
|
@@ -744,8 +744,8 @@ var SprigrLogValidationError = class extends Error {
|
|
|
744
744
|
field;
|
|
745
745
|
max;
|
|
746
746
|
length;
|
|
747
|
-
constructor(
|
|
748
|
-
super(
|
|
747
|
+
constructor(message2, fields) {
|
|
748
|
+
super(message2);
|
|
749
749
|
this.name = "SprigrLogValidationError";
|
|
750
750
|
this.index = fields.index;
|
|
751
751
|
this.field = fields.field;
|
|
@@ -869,13 +869,13 @@ async function postLog(env, entries, timeoutMs) {
|
|
|
869
869
|
return { ok: true, written: typeof reply.written === "number" ? reply.written : entries.length };
|
|
870
870
|
} catch (err) {
|
|
871
871
|
const e = err;
|
|
872
|
-
const
|
|
873
|
-
console.warn(`[sprigr-log] log fallback failed: ${
|
|
872
|
+
const message2 = e instanceof Error ? e.message : String(err);
|
|
873
|
+
console.warn(`[sprigr-log] log fallback failed: ${message2}`);
|
|
874
874
|
return {
|
|
875
875
|
ok: false,
|
|
876
876
|
error: e.error ?? (e.status !== void 0 ? "log_failed" : "log_transport_failed"),
|
|
877
877
|
...e.status !== void 0 ? { status: e.status } : {},
|
|
878
|
-
detail: e.detail ??
|
|
878
|
+
detail: e.detail ?? message2
|
|
879
879
|
};
|
|
880
880
|
}
|
|
881
881
|
}
|
|
@@ -924,8 +924,8 @@ var ACL_INDEX_SUFFIX = "-acl-files";
|
|
|
924
924
|
var SprigrDataValidationError = class extends Error {
|
|
925
925
|
error;
|
|
926
926
|
index;
|
|
927
|
-
constructor(
|
|
928
|
-
super(
|
|
927
|
+
constructor(message2, fields) {
|
|
928
|
+
super(message2);
|
|
929
929
|
this.name = "SprigrDataValidationError";
|
|
930
930
|
this.error = fields.error;
|
|
931
931
|
if (fields.index !== void 0) this.index = fields.index;
|
|
@@ -1098,7 +1098,7 @@ function base64urlDecode2(s) {
|
|
|
1098
1098
|
return null;
|
|
1099
1099
|
}
|
|
1100
1100
|
}
|
|
1101
|
-
async function hmacBytes(secret,
|
|
1101
|
+
async function hmacBytes(secret, message2) {
|
|
1102
1102
|
const key = await crypto.subtle.importKey(
|
|
1103
1103
|
"raw",
|
|
1104
1104
|
new TextEncoder().encode(secret),
|
|
@@ -1106,7 +1106,7 @@ async function hmacBytes(secret, message) {
|
|
|
1106
1106
|
false,
|
|
1107
1107
|
["sign"]
|
|
1108
1108
|
);
|
|
1109
|
-
return new Uint8Array(await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(
|
|
1109
|
+
return new Uint8Array(await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(message2)));
|
|
1110
1110
|
}
|
|
1111
1111
|
function constantTimeEqualBytes(a, b) {
|
|
1112
1112
|
if (a.byteLength !== b.byteLength) return false;
|
|
@@ -1197,8 +1197,8 @@ async function resolveViewerUserId(headers, env, options = {}) {
|
|
|
1197
1197
|
|
|
1198
1198
|
// src/tool-wrappers.ts
|
|
1199
1199
|
var NotConnectedError = class extends Error {
|
|
1200
|
-
constructor(
|
|
1201
|
-
super(
|
|
1200
|
+
constructor(message2 = "The calling actor has no connection with this app.") {
|
|
1201
|
+
super(message2);
|
|
1202
1202
|
this.name = "NotConnectedError";
|
|
1203
1203
|
}
|
|
1204
1204
|
};
|
|
@@ -1368,8 +1368,8 @@ function approvalPreview(value, max = APPROVAL_PREVIEW_MAX) {
|
|
|
1368
1368
|
|
|
1369
1369
|
// src/write-protection/undo-envelope.ts
|
|
1370
1370
|
var InvalidUndoEnvelopeError = class extends Error {
|
|
1371
|
-
constructor(
|
|
1372
|
-
super(
|
|
1371
|
+
constructor(message2) {
|
|
1372
|
+
super(message2);
|
|
1373
1373
|
this.name = "InvalidUndoEnvelopeError";
|
|
1374
1374
|
}
|
|
1375
1375
|
};
|
|
@@ -1470,6 +1470,23 @@ async function offerUndo(args) {
|
|
|
1470
1470
|
}
|
|
1471
1471
|
|
|
1472
1472
|
// src/write-protection/require-approval.ts
|
|
1473
|
+
var ATTESTATION_KEYS = ["confirm", APPROVAL_GRANTED_KEY];
|
|
1474
|
+
function canonicalJson(value) {
|
|
1475
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
1476
|
+
if (value && typeof value === "object") {
|
|
1477
|
+
const entries = Object.keys(value).filter((k) => value[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${canonicalJson(value[k])}`);
|
|
1478
|
+
return `{${entries.join(",")}}`;
|
|
1479
|
+
}
|
|
1480
|
+
return JSON.stringify(value ?? null);
|
|
1481
|
+
}
|
|
1482
|
+
function defaultPayloadParts(params, keys, connectionArgs = []) {
|
|
1483
|
+
const skip = /* @__PURE__ */ new Set([...keys, ...ATTESTATION_KEYS, ...connectionArgs]);
|
|
1484
|
+
const rest = {};
|
|
1485
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1486
|
+
if (!skip.has(k) && v !== void 0) rest[k] = v;
|
|
1487
|
+
}
|
|
1488
|
+
return Object.keys(rest).length ? [canonicalJson(rest)] : [];
|
|
1489
|
+
}
|
|
1473
1490
|
function rawIdOf(args, keys) {
|
|
1474
1491
|
for (const k of keys) {
|
|
1475
1492
|
const v = args[k];
|
|
@@ -1509,7 +1526,7 @@ async function askPass(name, spec, params, env, opts, hashPrefix) {
|
|
|
1509
1526
|
const pinned = await pin(opts, env, connection);
|
|
1510
1527
|
const describeTarget = spec.describeTarget ?? opts.describeTarget;
|
|
1511
1528
|
const target = rawId && describeTarget ? await safeLabel(describeTarget, pinned, rawId, name) : rawId || "(unknown id)";
|
|
1512
|
-
const extra = spec.hash ? spec.hash(params) :
|
|
1529
|
+
const extra = spec.hash ? spec.hash(params) : defaultPayloadParts(params, spec.keys, opts.connectionArgs);
|
|
1513
1530
|
const count = countOf(spec, params, rawId);
|
|
1514
1531
|
return {
|
|
1515
1532
|
ok: false,
|
|
@@ -1969,8 +1986,8 @@ function withSprigrInboxFallback(env) {
|
|
|
1969
1986
|
return overlaySprigr(env, { ...existing ?? {}, inbox: { append, folders } });
|
|
1970
1987
|
}
|
|
1971
1988
|
var InboxSendRefusal = class extends Error {
|
|
1972
|
-
constructor(code,
|
|
1973
|
-
super(
|
|
1989
|
+
constructor(code, message2) {
|
|
1990
|
+
super(message2);
|
|
1974
1991
|
this.code = code;
|
|
1975
1992
|
this.name = "InboxSendRefusal";
|
|
1976
1993
|
}
|
|
@@ -2046,6 +2063,137 @@ async function connectDisconnect(env, req) {
|
|
|
2046
2063
|
if (!bridge) throw new Error("connectDisconnect: SPRIGR_PLATFORM_BASE / SPRIGR_INSTALL_TOKEN are not bound");
|
|
2047
2064
|
return await installTokenPost(bridge, "/internal/wfp/connect/disconnect", req, { label: "connect disconnect" });
|
|
2048
2065
|
}
|
|
2066
|
+
|
|
2067
|
+
// src/data-purge.ts
|
|
2068
|
+
var BRIDGE_TIMEOUT_MS = 2e4;
|
|
2069
|
+
var DATA_DELETE_MAX_IDS = 1e3;
|
|
2070
|
+
function injectedData(env) {
|
|
2071
|
+
const data = env.SPRIGR?.data;
|
|
2072
|
+
return data && typeof data === "object" ? data : null;
|
|
2073
|
+
}
|
|
2074
|
+
function idsOpts(opts) {
|
|
2075
|
+
return {
|
|
2076
|
+
...opts?.index ? { index: opts.index } : {},
|
|
2077
|
+
...opts?.withAcl ? { withAcl: true } : {}
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
function makeDataClient(env) {
|
|
2081
|
+
const data = injectedData(env);
|
|
2082
|
+
if (data && typeof data.listIds === "function" && typeof data.delete === "function") {
|
|
2083
|
+
const d = data;
|
|
2084
|
+
return {
|
|
2085
|
+
via: "binding",
|
|
2086
|
+
import: (objects, opts) => d.import(objects, opts),
|
|
2087
|
+
search: (opts) => d.search(opts),
|
|
2088
|
+
get: (id, opts) => d.get(id, opts),
|
|
2089
|
+
partialUpdate: (objects, opts) => partialUpdateData(env, objects, opts),
|
|
2090
|
+
async delete(ids, opts) {
|
|
2091
|
+
const r = await d.delete(ids, opts);
|
|
2092
|
+
return { ok: r?.ok !== false, deleted: typeof r?.deleted === "number" ? r.deleted : ids.length, index: String(r?.index ?? opts?.index ?? "") };
|
|
2093
|
+
},
|
|
2094
|
+
async listIds(prefix, opts) {
|
|
2095
|
+
const r = await d.listIds(prefix, opts);
|
|
2096
|
+
const objectIDs = Array.isArray(r?.objectIDs) ? r.objectIDs : [];
|
|
2097
|
+
return { objectIDs, total: typeof r?.total === "number" ? r.total : objectIDs.length, truncated: r?.truncated === true };
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
const bridge = resolveInstallBridge(env);
|
|
2102
|
+
if (!bridge) return null;
|
|
2103
|
+
const post = (path, body, label) => installTokenPost(bridge, path, body, { label, timeoutMs: BRIDGE_TIMEOUT_MS });
|
|
2104
|
+
return {
|
|
2105
|
+
via: "http",
|
|
2106
|
+
async import(objects, opts) {
|
|
2107
|
+
const r = await post("/internal/wfp/data/import", { objects, ...opts ?? {} }, "data.import");
|
|
2108
|
+
return { ok: r.ok !== false, indexed: typeof r.indexed === "number" ? r.indexed : objects.length, index: String(r.index ?? opts?.index ?? "") };
|
|
2109
|
+
},
|
|
2110
|
+
async search(opts) {
|
|
2111
|
+
return await post("/internal/wfp/data/search", { ...opts ?? {} }, "data.search");
|
|
2112
|
+
},
|
|
2113
|
+
async get(objectID, opts) {
|
|
2114
|
+
const r = await post("/internal/wfp/data/get", { objectID, ...opts?.index ? { index: opts.index } : {} }, "data.get");
|
|
2115
|
+
return { ok: r.ok !== false, object: r.object ?? null, index: String(r.index ?? opts?.index ?? "") };
|
|
2116
|
+
},
|
|
2117
|
+
partialUpdate: (objects, opts) => partialUpdateData(env, objects, opts),
|
|
2118
|
+
async delete(objectIDs, opts) {
|
|
2119
|
+
const r = await post("/internal/wfp/data/delete", { objectIDs, ...idsOpts(opts) }, "data.delete");
|
|
2120
|
+
return { ok: r.ok !== false, deleted: typeof r.deleted === "number" ? r.deleted : objectIDs.length, index: String(r.index ?? opts?.index ?? "") };
|
|
2121
|
+
},
|
|
2122
|
+
async listIds(prefix, opts) {
|
|
2123
|
+
const r = await post("/internal/wfp/data/list-ids", { prefix, ...idsOpts(opts) }, "data.listIds");
|
|
2124
|
+
const objectIDs = Array.isArray(r.objectIDs) ? r.objectIDs : [];
|
|
2125
|
+
return { objectIDs, total: typeof r.total === "number" ? r.total : objectIDs.length, truncated: r.truncated === true };
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
var message = (err) => err instanceof Error ? err.message : String(err);
|
|
2130
|
+
function groupKey(index, withAcl) {
|
|
2131
|
+
return `${withAcl ? "acl" : "plain"}\0${index ?? ""}`;
|
|
2132
|
+
}
|
|
2133
|
+
async function snapshotIndexIds(env, prefixes) {
|
|
2134
|
+
const client = makeDataClient(env);
|
|
2135
|
+
const snap = { groups: [], listed: 0, truncated: false, via: client?.via ?? "none" };
|
|
2136
|
+
if (!client) return snap;
|
|
2137
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
2138
|
+
try {
|
|
2139
|
+
for (const spec of prefixes) {
|
|
2140
|
+
const s = typeof spec === "string" ? { prefix: spec } : spec;
|
|
2141
|
+
if (!s.prefix) throw new Error("every prefix must be non-empty (an empty one would list the whole index)");
|
|
2142
|
+
const key = groupKey(s.index, s.withAcl);
|
|
2143
|
+
let group = byGroup.get(key);
|
|
2144
|
+
if (!group) {
|
|
2145
|
+
group = { ...s.index ? { index: s.index } : {}, ...s.withAcl ? { withAcl: true } : {}, ids: /* @__PURE__ */ new Set() };
|
|
2146
|
+
byGroup.set(key, group);
|
|
2147
|
+
}
|
|
2148
|
+
const r = await client.listIds(s.prefix, { index: s.index, withAcl: s.withAcl });
|
|
2149
|
+
r.objectIDs.forEach((id) => {
|
|
2150
|
+
if (id.startsWith(s.prefix)) group.ids.add(id);
|
|
2151
|
+
});
|
|
2152
|
+
snap.truncated ||= r.truncated;
|
|
2153
|
+
}
|
|
2154
|
+
} catch (err) {
|
|
2155
|
+
snap.error = `list: ${message(err)}`;
|
|
2156
|
+
}
|
|
2157
|
+
for (const g of byGroup.values()) {
|
|
2158
|
+
snap.groups.push({ ...g.index ? { index: g.index } : {}, ...g.withAcl ? { withAcl: true } : {}, ids: [...g.ids] });
|
|
2159
|
+
snap.listed += g.ids.size;
|
|
2160
|
+
}
|
|
2161
|
+
return snap;
|
|
2162
|
+
}
|
|
2163
|
+
async function deleteSnapshotIds(env, snapshot, opts) {
|
|
2164
|
+
const res = {
|
|
2165
|
+
deleted: 0,
|
|
2166
|
+
listed: snapshot.listed,
|
|
2167
|
+
truncated: snapshot.truncated,
|
|
2168
|
+
via: snapshot.via,
|
|
2169
|
+
...snapshot.error ? { error: snapshot.error } : {}
|
|
2170
|
+
};
|
|
2171
|
+
if (snapshot.listed === 0) return res;
|
|
2172
|
+
const client = makeDataClient(env);
|
|
2173
|
+
if (!client) {
|
|
2174
|
+
res.via = "none";
|
|
2175
|
+
res.error = [res.error, "delete: no data path (env.SPRIGR.data and the install token are both absent)"].filter(Boolean).join("; ");
|
|
2176
|
+
return res;
|
|
2177
|
+
}
|
|
2178
|
+
res.via = client.via;
|
|
2179
|
+
const chunk = Math.min(Math.max(Math.trunc(opts?.chunk ?? DATA_DELETE_MAX_IDS), 1), DATA_DELETE_MAX_IDS);
|
|
2180
|
+
try {
|
|
2181
|
+
for (const g of snapshot.groups) {
|
|
2182
|
+
for (let i = 0; i < g.ids.length; i += chunk) {
|
|
2183
|
+
const ids = g.ids.slice(i, i + chunk);
|
|
2184
|
+
const r = await client.delete(ids, { index: g.index, withAcl: g.withAcl });
|
|
2185
|
+
if (!r.ok) throw new Error(`the platform refused ${ids.length} id(s)${g.index ? ` in ${g.index}` : ""}`);
|
|
2186
|
+
res.deleted += r.deleted;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
} catch (err) {
|
|
2190
|
+
res.error = [res.error, `delete: ${message(err)}`].filter(Boolean).join("; ");
|
|
2191
|
+
}
|
|
2192
|
+
return res;
|
|
2193
|
+
}
|
|
2194
|
+
async function purgeIndexByPrefix(env, prefixes, opts) {
|
|
2195
|
+
return deleteSnapshotIds(env, await snapshotIndexIds(env, prefixes), opts);
|
|
2196
|
+
}
|
|
2049
2197
|
export {
|
|
2050
2198
|
ACTOR_RETIRED_HOOK_TOOL,
|
|
2051
2199
|
ACTOR_RETIRE_REASONS,
|
|
@@ -2053,6 +2201,7 @@ export {
|
|
|
2053
2201
|
APPROVAL_PREVIEW_MAX,
|
|
2054
2202
|
APP_FILES_ROOT,
|
|
2055
2203
|
APP_OWNER_SEGMENT,
|
|
2204
|
+
DATA_DELETE_MAX_IDS,
|
|
2056
2205
|
DATA_PARTIAL_UPDATE_PATH,
|
|
2057
2206
|
DEFAULT_EMIT_TIMEOUT_MS,
|
|
2058
2207
|
DEFAULT_FILE_READ_TIMEOUT_MS,
|
|
@@ -2110,6 +2259,7 @@ export {
|
|
|
2110
2259
|
decodeState,
|
|
2111
2260
|
defineInboxSendHandler,
|
|
2112
2261
|
deleteAppFile,
|
|
2262
|
+
deleteSnapshotIds,
|
|
2113
2263
|
deriveConfirmationPolicy,
|
|
2114
2264
|
describeMissingBridge,
|
|
2115
2265
|
dispatcherApproval,
|
|
@@ -2126,6 +2276,7 @@ export {
|
|
|
2126
2276
|
isStagingHost,
|
|
2127
2277
|
listAppFiles,
|
|
2128
2278
|
logToPlatform,
|
|
2279
|
+
makeDataClient,
|
|
2129
2280
|
manifestIsFresh,
|
|
2130
2281
|
offerUndo,
|
|
2131
2282
|
openFileRef,
|
|
@@ -2134,6 +2285,7 @@ export {
|
|
|
2134
2285
|
parseActor,
|
|
2135
2286
|
parseActorRetiredArgs,
|
|
2136
2287
|
partialUpdateData,
|
|
2288
|
+
purgeIndexByPrefix,
|
|
2137
2289
|
putAppFile,
|
|
2138
2290
|
putAppFileStream,
|
|
2139
2291
|
randomHex,
|
|
@@ -2154,6 +2306,7 @@ export {
|
|
|
2154
2306
|
seq,
|
|
2155
2307
|
serializeManifest,
|
|
2156
2308
|
set,
|
|
2309
|
+
snapshotIndexIds,
|
|
2157
2310
|
tool,
|
|
2158
2311
|
undoEnvelope,
|
|
2159
2312
|
validateLogEntries,
|