@nestm/storage 0.1.0-alpha.2 → 0.1.0-alpha.20
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 +320 -0
- package/README.md +975 -29
- package/SECURITY.md +128 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts +53 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts.map +1 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.js +370 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.js.map +1 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +91 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts.map +1 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.js +497 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.js.map +1 -0
- package/dist/ai-sdk/index.d.ts +3 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +3 -0
- package/dist/ai-sdk/index.js.map +1 -0
- package/dist/bytes/index.d.ts +30 -0
- package/dist/bytes/index.d.ts.map +1 -0
- package/dist/bytes/index.js +96 -0
- package/dist/bytes/index.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/storage-staged-content.d.ts +39 -0
- package/dist/core/storage-staged-content.d.ts.map +1 -0
- package/dist/core/storage-staged-content.js +109 -0
- package/dist/core/storage-staged-content.js.map +1 -0
- package/dist/core/storage-streams.d.ts +19 -0
- package/dist/core/storage-streams.d.ts.map +1 -0
- package/dist/core/storage-streams.js +95 -0
- package/dist/core/storage-streams.js.map +1 -0
- package/dist/core/storage-text-edit.d.ts +38 -0
- package/dist/core/storage-text-edit.d.ts.map +1 -0
- package/dist/core/storage-text-edit.js +86 -0
- package/dist/core/storage-text-edit.js.map +1 -0
- package/dist/core/storage-text-stream-edit.d.ts +8 -0
- package/dist/core/storage-text-stream-edit.d.ts.map +1 -0
- package/dist/core/storage-text-stream-edit.js +114 -0
- package/dist/core/storage-text-stream-edit.js.map +1 -0
- package/dist/core/storage-text.d.ts +22 -0
- package/dist/core/storage-text.d.ts.map +1 -0
- package/dist/core/storage-text.js +69 -0
- package/dist/core/storage-text.js.map +1 -0
- package/dist/crypto/index.d.ts +2 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +2 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/storage-encrypted-content.d.ts +49 -0
- package/dist/crypto/storage-encrypted-content.d.ts.map +1 -0
- package/dist/crypto/storage-encrypted-content.js +212 -0
- package/dist/crypto/storage-encrypted-content.js.map +1 -0
- package/dist/files-sdk/azure/azure-conditional.d.ts +5 -0
- package/dist/files-sdk/azure/azure-conditional.d.ts.map +1 -0
- package/dist/files-sdk/azure/azure-conditional.js +184 -0
- package/dist/files-sdk/azure/azure-conditional.js.map +1 -0
- package/dist/files-sdk/azure/index.d.ts +10 -0
- package/dist/files-sdk/azure/index.d.ts.map +1 -0
- package/dist/files-sdk/azure/index.js +34 -0
- package/dist/files-sdk/azure/index.js.map +1 -0
- package/dist/files-sdk/files-sdk.driver.d.ts +85 -3
- package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
- package/dist/files-sdk/files-sdk.driver.js +1437 -37
- package/dist/files-sdk/files-sdk.driver.js.map +1 -1
- package/dist/files-sdk/fs/index.d.ts +42 -0
- package/dist/files-sdk/fs/index.d.ts.map +1 -0
- package/dist/files-sdk/fs/index.js +1117 -0
- package/dist/files-sdk/fs/index.js.map +1 -0
- package/dist/files-sdk/index.d.ts +1 -1
- package/dist/files-sdk/index.d.ts.map +1 -1
- package/dist/files-sdk/index.js.map +1 -1
- package/dist/files-sdk/memory.d.ts +7 -0
- package/dist/files-sdk/memory.d.ts.map +1 -0
- package/dist/files-sdk/memory.js +72 -0
- package/dist/files-sdk/memory.js.map +1 -0
- package/dist/files-sdk/provider/index.d.ts +58 -0
- package/dist/files-sdk/provider/index.d.ts.map +1 -0
- package/dist/files-sdk/provider/index.js +169 -0
- package/dist/files-sdk/provider/index.js.map +1 -0
- package/dist/files-sdk/s3/construction-metadata.d.ts +9 -0
- package/dist/files-sdk/s3/construction-metadata.d.ts.map +1 -0
- package/dist/files-sdk/s3/construction-metadata.js +24 -0
- package/dist/files-sdk/s3/construction-metadata.js.map +1 -0
- package/dist/files-sdk/s3/index.d.ts +54 -0
- package/dist/files-sdk/s3/index.d.ts.map +1 -0
- package/dist/files-sdk/s3/index.js +1505 -0
- package/dist/files-sdk/s3/index.js.map +1 -0
- package/dist/gateway/index.d.ts +1 -1
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/storage-gateway-fastify-parser.d.ts.map +1 -1
- package/dist/gateway/storage-gateway-fastify-parser.js.map +1 -1
- package/dist/gateway/storage-gateway.controller.d.ts +12 -11
- package/dist/gateway/storage-gateway.controller.d.ts.map +1 -1
- package/dist/gateway/storage-gateway.controller.js +240 -70
- package/dist/gateway/storage-gateway.controller.js.map +1 -1
- package/dist/gateway/storage-gateway.guard.d.ts.map +1 -1
- package/dist/gateway/storage-gateway.guard.js.map +1 -1
- package/dist/gateway/storage-gateway.module.d.ts.map +1 -1
- package/dist/gateway/storage-gateway.module.js +60 -1
- package/dist/gateway/storage-gateway.module.js.map +1 -1
- package/dist/gateway/storage-gateway.tokens.d.ts +1 -0
- package/dist/gateway/storage-gateway.tokens.d.ts.map +1 -1
- package/dist/gateway/storage-gateway.tokens.js +1 -0
- package/dist/gateway/storage-gateway.tokens.js.map +1 -1
- package/dist/gateway/storage-gateway.types.d.ts +53 -10
- package/dist/gateway/storage-gateway.types.d.ts.map +1 -1
- package/dist/gateway/storage-gateway.types.js.map +1 -1
- package/dist/inject-storage.decorator.js.map +1 -1
- package/dist/storage-etag.d.ts +13 -0
- package/dist/storage-etag.d.ts.map +1 -0
- package/dist/storage-etag.js +31 -0
- package/dist/storage-etag.js.map +1 -0
- package/dist/storage-upload-control.d.ts.map +1 -1
- package/dist/storage.client.d.ts +14 -1
- package/dist/storage.client.d.ts.map +1 -1
- package/dist/storage.client.js +204 -2
- package/dist/storage.client.js.map +1 -1
- package/dist/storage.driver.d.ts +28 -1
- package/dist/storage.driver.d.ts.map +1 -1
- package/dist/storage.driver.js.map +1 -1
- package/dist/storage.error.d.ts +17 -10
- package/dist/storage.error.d.ts.map +1 -1
- package/dist/storage.error.js +47 -1
- package/dist/storage.error.js.map +1 -1
- package/dist/storage.module.d.ts.map +1 -1
- package/dist/storage.module.js.map +1 -1
- package/dist/storage.service.d.ts.map +1 -1
- package/dist/storage.service.js +28 -3
- package/dist/storage.service.js.map +1 -1
- package/dist/storage.tokens.js.map +1 -1
- package/dist/storage.types.d.ts +150 -1
- package/dist/storage.types.d.ts.map +1 -1
- package/dist/storage.types.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +3 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/provider-conformance.d.ts +65 -0
- package/dist/testing/provider-conformance.d.ts.map +1 -0
- package/dist/testing/provider-conformance.js +869 -0
- package/dist/testing/provider-conformance.js.map +1 -0
- package/dist/workspace/index.d.ts +12 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +10 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/storage-catalog-checkout.d.ts +7 -0
- package/dist/workspace/storage-catalog-checkout.d.ts.map +1 -0
- package/dist/workspace/storage-catalog-checkout.js +13 -0
- package/dist/workspace/storage-catalog-checkout.js.map +1 -0
- package/dist/workspace/storage-draft-stream.d.ts +3 -0
- package/dist/workspace/storage-draft-stream.d.ts.map +1 -0
- package/dist/workspace/storage-draft-stream.js +57 -0
- package/dist/workspace/storage-draft-stream.js.map +1 -0
- package/dist/workspace/storage-file-catalog.types.d.ts +73 -0
- package/dist/workspace/storage-file-catalog.types.d.ts.map +1 -0
- package/dist/workspace/storage-file-catalog.types.js +2 -0
- package/dist/workspace/storage-file-catalog.types.js.map +1 -0
- package/dist/workspace/storage-file-workflow.d.ts +7 -0
- package/dist/workspace/storage-file-workflow.d.ts.map +1 -0
- package/dist/workspace/storage-file-workflow.js +657 -0
- package/dist/workspace/storage-file-workflow.js.map +1 -0
- package/dist/workspace/storage-file-workflow.protection.d.ts +31 -0
- package/dist/workspace/storage-file-workflow.protection.d.ts.map +1 -0
- package/dist/workspace/storage-file-workflow.protection.js +339 -0
- package/dist/workspace/storage-file-workflow.protection.js.map +1 -0
- package/dist/workspace/storage-file-workflow.types.d.ts +184 -0
- package/dist/workspace/storage-file-workflow.types.d.ts.map +1 -0
- package/dist/workspace/storage-file-workflow.types.js +10 -0
- package/dist/workspace/storage-file-workflow.types.js.map +1 -0
- package/dist/workspace/storage-text-draft.d.ts +21 -0
- package/dist/workspace/storage-text-draft.d.ts.map +1 -0
- package/dist/workspace/storage-text-draft.js +77 -0
- package/dist/workspace/storage-text-draft.js.map +1 -0
- package/dist/workspace/storage-working-files.d.ts +34 -0
- package/dist/workspace/storage-working-files.d.ts.map +1 -0
- package/dist/workspace/storage-working-files.js +326 -0
- package/dist/workspace/storage-working-files.js.map +1 -0
- package/dist/workspace/storage-workspace.cursor.d.ts +71 -0
- package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.cursor.js +408 -0
- package/dist/workspace/storage-workspace.cursor.js.map +1 -0
- package/dist/workspace/storage-workspace.d.ts +6 -0
- package/dist/workspace/storage-workspace.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.error.d.ts +32 -0
- package/dist/workspace/storage-workspace.error.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.error.js +75 -0
- package/dist/workspace/storage-workspace.error.js.map +1 -0
- package/dist/workspace/storage-workspace.js +849 -0
- package/dist/workspace/storage-workspace.js.map +1 -0
- package/dist/workspace/storage-workspace.path.d.ts +9 -0
- package/dist/workspace/storage-workspace.path.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.path.js +68 -0
- package/dist/workspace/storage-workspace.path.js.map +1 -0
- package/dist/workspace/storage-workspace.types.d.ts +123 -0
- package/dist/workspace/storage-workspace.types.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.types.js +22 -0
- package/dist/workspace/storage-workspace.types.js.map +1 -0
- package/package.json +99 -20
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { StorageError, isStorageError } from '../storage.error.js';
|
|
3
|
+
import { storageBytesStream, storageInteger } from '../core/storage-streams.js';
|
|
4
|
+
import { editStorageTextStream } from '../core/storage-text-stream-edit.js';
|
|
5
|
+
/** A path-based editing view over durable checkpoints. Saved heads change only on commit. */
|
|
6
|
+
export class StorageWorkingFiles {
|
|
7
|
+
files;
|
|
8
|
+
workflow;
|
|
9
|
+
catalog;
|
|
10
|
+
constructor(files, workflow) {
|
|
11
|
+
this.files = files;
|
|
12
|
+
this.workflow = workflow;
|
|
13
|
+
this.catalog = Object.freeze({
|
|
14
|
+
...files,
|
|
15
|
+
list: (input) => this.page(input, 'list'),
|
|
16
|
+
search: (input) => this.page(input, 'search'),
|
|
17
|
+
stat: async (input) => {
|
|
18
|
+
const draft = await this.draft(input);
|
|
19
|
+
return draft && draft.status !== 'committed'
|
|
20
|
+
? this.receipt(draft)
|
|
21
|
+
: files.stat(this.saved(input, draft));
|
|
22
|
+
},
|
|
23
|
+
readWindow: async (input) => {
|
|
24
|
+
const draft = await this.draft(input);
|
|
25
|
+
if (!draft || draft.status === 'committed')
|
|
26
|
+
return files.readWindow(this.saved(input, draft));
|
|
27
|
+
const page = await workflow.read({
|
|
28
|
+
draftId: draft.id,
|
|
29
|
+
offset: input.offset,
|
|
30
|
+
signal: input.signal,
|
|
31
|
+
});
|
|
32
|
+
if (page.size !== draft.size)
|
|
33
|
+
this.conflict();
|
|
34
|
+
return {
|
|
35
|
+
...this.receipt(draft),
|
|
36
|
+
content: page.content,
|
|
37
|
+
offset: page.offset,
|
|
38
|
+
nextOffset: page.nextOffset,
|
|
39
|
+
totalBytes: page.size,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
readStream: async (input) => {
|
|
43
|
+
const draft = await this.draft(input);
|
|
44
|
+
if (!draft || draft.status === 'committed')
|
|
45
|
+
return files.readStream(this.saved(input, draft));
|
|
46
|
+
const stream = await workflow.readStream({
|
|
47
|
+
draftId: draft.id,
|
|
48
|
+
expectedSize: draft.size,
|
|
49
|
+
start: input.start,
|
|
50
|
+
end: input.end,
|
|
51
|
+
signal: input.signal,
|
|
52
|
+
});
|
|
53
|
+
return { ...this.receipt(draft), body: stream.body };
|
|
54
|
+
},
|
|
55
|
+
searchContent: async (input) => {
|
|
56
|
+
const draft = await this.draft(input);
|
|
57
|
+
if (!draft || draft.status === 'committed')
|
|
58
|
+
return files.searchContent(this.saved(input, draft));
|
|
59
|
+
return workflow.searchText({
|
|
60
|
+
draftId: draft.id,
|
|
61
|
+
expectedSize: draft.size,
|
|
62
|
+
query: input.query,
|
|
63
|
+
offset: input.offset,
|
|
64
|
+
signal: input.signal,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
write: (input) => this.write(input),
|
|
68
|
+
edit: async (input) => {
|
|
69
|
+
this.requireWrite();
|
|
70
|
+
const changes = input.change.kind === 'batch' ? input.change.changes : [input.change];
|
|
71
|
+
this.textLimit(changes
|
|
72
|
+
.map((change) => change.kind === 'append'
|
|
73
|
+
? change.text
|
|
74
|
+
: change.oldText + change.newText)
|
|
75
|
+
.join(''));
|
|
76
|
+
const prior = await workflow.lookup({
|
|
77
|
+
idempotencyKey: input.commandId,
|
|
78
|
+
signal: input.signal,
|
|
79
|
+
});
|
|
80
|
+
const source = prior?.sourceDraftId
|
|
81
|
+
? await workflow.read({
|
|
82
|
+
draftId: prior.sourceDraftId,
|
|
83
|
+
signal: input.signal,
|
|
84
|
+
})
|
|
85
|
+
: await this.draft(input);
|
|
86
|
+
if (!source || (!prior && source.status === 'committed')) {
|
|
87
|
+
const saved = this.saved(input, source);
|
|
88
|
+
const result = await workflow.stageStream({
|
|
89
|
+
path: input.path,
|
|
90
|
+
expectedEtag: saved.expectedEtag,
|
|
91
|
+
text: true,
|
|
92
|
+
signal: input.signal,
|
|
93
|
+
idempotencyKey: input.commandId,
|
|
94
|
+
contentIdentity: createHash('sha256')
|
|
95
|
+
.update(JSON.stringify([
|
|
96
|
+
'catalog-edit',
|
|
97
|
+
input.path,
|
|
98
|
+
input.expectedEtag,
|
|
99
|
+
changes,
|
|
100
|
+
]))
|
|
101
|
+
.digest('hex'),
|
|
102
|
+
body: async () => {
|
|
103
|
+
const stream = await files.readStream(saved);
|
|
104
|
+
return editStorageTextStream(stream.body, changes, {
|
|
105
|
+
maxEditBytes: files.limits.maxWriteBytes,
|
|
106
|
+
maxEdits: workflow.limits.maxEdits,
|
|
107
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
return this.result(result);
|
|
112
|
+
}
|
|
113
|
+
const result = await workflow.reviseText({
|
|
114
|
+
draftId: source.id,
|
|
115
|
+
expectedSize: source.size,
|
|
116
|
+
changes,
|
|
117
|
+
requestIdentity: JSON.stringify([input.path, input.expectedEtag]),
|
|
118
|
+
idempotencyKey: input.commandId,
|
|
119
|
+
signal: input.signal,
|
|
120
|
+
});
|
|
121
|
+
// The workflow fingerprint includes the source, but the host also fences its public path.
|
|
122
|
+
if (result.path !== input.path)
|
|
123
|
+
this.conflict();
|
|
124
|
+
return this.result(result);
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async write(input) {
|
|
129
|
+
this.requireWrite();
|
|
130
|
+
this.textLimit(input.content);
|
|
131
|
+
const prior = await this.workflow.lookup({
|
|
132
|
+
idempotencyKey: input.commandId,
|
|
133
|
+
signal: input.signal,
|
|
134
|
+
});
|
|
135
|
+
let source = prior?.sourceDraftId
|
|
136
|
+
? await this.workflow.read({
|
|
137
|
+
draftId: prior.sourceDraftId,
|
|
138
|
+
signal: input.signal,
|
|
139
|
+
})
|
|
140
|
+
: null;
|
|
141
|
+
let originalEtag = prior?.expectedEtag ?? undefined;
|
|
142
|
+
if (!prior) {
|
|
143
|
+
source = await this.draft(input);
|
|
144
|
+
const saved = this.saved(input, source);
|
|
145
|
+
if (input.expectedEtag === undefined) {
|
|
146
|
+
if (source)
|
|
147
|
+
this.conflict();
|
|
148
|
+
try {
|
|
149
|
+
await this.files.stat(input);
|
|
150
|
+
this.conflict();
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (!isStorageError(error) || error.code !== 'NOT_FOUND')
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (!source || source.status === 'committed') {
|
|
158
|
+
const file = await this.files.stat(saved);
|
|
159
|
+
if (file.etag !== saved.expectedEtag)
|
|
160
|
+
this.conflict();
|
|
161
|
+
}
|
|
162
|
+
if (source?.status === 'committed')
|
|
163
|
+
source = null;
|
|
164
|
+
originalEtag = source
|
|
165
|
+
? (source.expectedEtag ?? undefined)
|
|
166
|
+
: saved.expectedEtag;
|
|
167
|
+
}
|
|
168
|
+
const bytes = new TextEncoder().encode(input.content);
|
|
169
|
+
const result = await this.workflow.stageStream({
|
|
170
|
+
path: input.path,
|
|
171
|
+
text: true,
|
|
172
|
+
idempotencyKey: input.commandId,
|
|
173
|
+
expectedEtag: originalEtag,
|
|
174
|
+
contentIdentity: createHash('sha256')
|
|
175
|
+
.update(JSON.stringify([input.expectedEtag ?? null, input.content]))
|
|
176
|
+
.digest('hex'),
|
|
177
|
+
body: () => storageBytesStream(bytes),
|
|
178
|
+
signal: input.signal,
|
|
179
|
+
...(source
|
|
180
|
+
? { sourceDraftId: source.id, expectedSize: source.size }
|
|
181
|
+
: {}),
|
|
182
|
+
});
|
|
183
|
+
return this.result(result);
|
|
184
|
+
}
|
|
185
|
+
/** Resolve an exact candidate (including committed replay) or the unique unfinished leaf. */
|
|
186
|
+
async draft(input) {
|
|
187
|
+
if (!this.files.allows('read'))
|
|
188
|
+
this.denied();
|
|
189
|
+
if (input.expectedEtag !== undefined) {
|
|
190
|
+
try {
|
|
191
|
+
const draft = await this.workflow.read({
|
|
192
|
+
draftId: input.expectedEtag,
|
|
193
|
+
signal: input.signal,
|
|
194
|
+
});
|
|
195
|
+
if (draft.path !== input.path || draft.status === 'cancelled')
|
|
196
|
+
this.conflict();
|
|
197
|
+
return draft;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
if (!isStorageError(error) || error.code !== 'NOT_FOUND')
|
|
201
|
+
throw error;
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const matches = (await this.pending(input)).filter((draft) => draft.path === input.path);
|
|
206
|
+
if (matches.length > 1)
|
|
207
|
+
throw new StorageError('Several unfinished revisions exist. Read an exact listed ETag before editing.', { code: 'CONFLICT' });
|
|
208
|
+
return matches[0] ?? null;
|
|
209
|
+
}
|
|
210
|
+
/** Discovery derives from persisted lineage, so process restarts need no local registry. */
|
|
211
|
+
async pending(input) {
|
|
212
|
+
if (!this.files.allows('read'))
|
|
213
|
+
this.denied();
|
|
214
|
+
const drafts = [];
|
|
215
|
+
let offset = 0;
|
|
216
|
+
do {
|
|
217
|
+
const page = await this.workflow.list({ offset, signal: input.signal });
|
|
218
|
+
drafts.push(...page.items);
|
|
219
|
+
if (page.nextOffset !== null && page.nextOffset <= offset)
|
|
220
|
+
throw new StorageError('Invalid draft pagination.', {
|
|
221
|
+
code: 'PROVIDER',
|
|
222
|
+
});
|
|
223
|
+
offset = page.nextOffset;
|
|
224
|
+
} while (offset !== null);
|
|
225
|
+
const predecessors = new Set(drafts.flatMap((draft) => draft.status !== 'cancelled' && draft.sourceDraftId
|
|
226
|
+
? [draft.sourceDraftId]
|
|
227
|
+
: []));
|
|
228
|
+
return drafts.filter((draft) => ['open', 'sealed'].includes(draft.status) &&
|
|
229
|
+
!predecessors.has(draft.id));
|
|
230
|
+
}
|
|
231
|
+
async page(input, mode) {
|
|
232
|
+
const offset = input.offset ?? 0;
|
|
233
|
+
storageInteger(offset, 'offset', 0);
|
|
234
|
+
const pending = await this.pending(input);
|
|
235
|
+
const paths = new Set(pending.map((draft) => draft.path));
|
|
236
|
+
const items = [];
|
|
237
|
+
const savedByPath = new Map();
|
|
238
|
+
let cursor = 0;
|
|
239
|
+
do {
|
|
240
|
+
const page = mode === 'list'
|
|
241
|
+
? await this.files.list({ ...input, offset: cursor })
|
|
242
|
+
: await this.files.search({
|
|
243
|
+
...input,
|
|
244
|
+
query: input.query,
|
|
245
|
+
offset: cursor,
|
|
246
|
+
});
|
|
247
|
+
for (const file of page.items)
|
|
248
|
+
savedByPath.set(file.path, file);
|
|
249
|
+
items.push(...page.items.filter((file) => !paths.has(file.path)));
|
|
250
|
+
if (page.nextOffset !== null && page.nextOffset <= cursor)
|
|
251
|
+
throw new StorageError('Invalid catalog pagination.', {
|
|
252
|
+
code: 'PROVIDER',
|
|
253
|
+
});
|
|
254
|
+
cursor = page.nextOffset;
|
|
255
|
+
} while (cursor !== null);
|
|
256
|
+
const directory = input.directory?.replace(/\/$/u, '');
|
|
257
|
+
items.push(...pending
|
|
258
|
+
.filter((draft) => mode === 'search'
|
|
259
|
+
? draft.path.toLowerCase().includes(input.query.toLowerCase())
|
|
260
|
+
: !directory ||
|
|
261
|
+
directory === '.' ||
|
|
262
|
+
draft.path.startsWith(`${directory}/`))
|
|
263
|
+
.map((draft) => ({
|
|
264
|
+
...savedByPath.get(draft.path),
|
|
265
|
+
...this.receipt(draft),
|
|
266
|
+
})));
|
|
267
|
+
items.sort((a, b) => a.path.localeCompare(b.path) || a.etag.localeCompare(b.etag));
|
|
268
|
+
const next = offset + this.files.limits.maxPageSize;
|
|
269
|
+
return {
|
|
270
|
+
items: items.slice(offset, next),
|
|
271
|
+
nextOffset: next < items.length ? next : null,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
saved(input, draft) {
|
|
275
|
+
if (draft?.status !== 'committed')
|
|
276
|
+
return input;
|
|
277
|
+
if (!draft.result || draft.result.path !== input.path)
|
|
278
|
+
this.conflict();
|
|
279
|
+
return { ...input, expectedEtag: draft.result.etag };
|
|
280
|
+
}
|
|
281
|
+
result(draft) {
|
|
282
|
+
if (draft.status === 'cancelled')
|
|
283
|
+
this.conflict();
|
|
284
|
+
if (draft.status === 'committed') {
|
|
285
|
+
if (!draft.result)
|
|
286
|
+
this.conflict();
|
|
287
|
+
return draft.result;
|
|
288
|
+
}
|
|
289
|
+
return this.receipt(draft);
|
|
290
|
+
}
|
|
291
|
+
receipt(draft) {
|
|
292
|
+
return {
|
|
293
|
+
path: draft.path,
|
|
294
|
+
fileId: draft.id,
|
|
295
|
+
etag: draft.id,
|
|
296
|
+
size: draft.size,
|
|
297
|
+
contentType: draft.text ? 'text/plain' : 'application/octet-stream',
|
|
298
|
+
operation: draft.expectedEtag === null ? 'created' : 'updated',
|
|
299
|
+
pending: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
textLimit(text) {
|
|
303
|
+
if (/[\uD800-\uDFFF]/u.test(text))
|
|
304
|
+
throw new StorageError('Text must be well-formed UTF-8.', {
|
|
305
|
+
code: 'INVALID_ARGUMENT',
|
|
306
|
+
});
|
|
307
|
+
if (new TextEncoder().encode(text).byteLength >
|
|
308
|
+
this.files.limits.maxWriteBytes)
|
|
309
|
+
throw new StorageError('Write exceeds the per-call text limit.', {
|
|
310
|
+
code: 'LIMIT_EXCEEDED',
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
requireWrite() {
|
|
314
|
+
if (!this.files.allows('write'))
|
|
315
|
+
this.denied();
|
|
316
|
+
}
|
|
317
|
+
denied() {
|
|
318
|
+
throw new StorageError('Working file operation is not permitted.', {
|
|
319
|
+
code: 'UNAUTHORIZED',
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
conflict() {
|
|
323
|
+
throw new StorageError('The working file revision changed. Read the current file before editing.', { code: 'CONFLICT' });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=storage-working-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-working-files.js","sourceRoot":"","sources":["../../src/workspace/storage-working-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAyB5E,6FAA6F;AAC7F,MAAM,OAAO,mBAAmB;IAGnB,KAAK;IACL,QAAQ;IAHV,OAAO,CAA6D;IAC7E,YACW,KAA4C,EAC5C,QAAgD;qBADhD,KAAK;wBACL,QAAQ;QAEjB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAE1B;YACA,GAAG,KAAK;YACR,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;YACzC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC;YAC7C,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACpB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtC,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;oBAC1C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;oBACrB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;YAC3C,CAAC;YACD,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBAC1B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;oBACxC,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;gBACpD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;oBAC/B,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBACH,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;oBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC9C,OAAO;oBACL,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;oBACtB,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,UAAU,EAAE,IAAI,CAAC,IAAI;iBACtB,CAAC;YACJ,CAAC;YACD,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBAC1B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;oBACxC,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;gBACpD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC;oBACvC,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,YAAY,EAAE,KAAK,CAAC,IAAI;oBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBACH,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;YACvD,CAAC;YACD,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBAC7B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;oBACxC,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;gBACvD,OAAO,QAAQ,CAAC,UAAU,CAAC;oBACzB,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,YAAY,EAAE,KAAK,CAAC,IAAI;oBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;YACL,CAAC;YACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;YACnC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACpB,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM,OAAO,GACX,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACxE,IAAI,CAAC,SAAS,CACZ,OAAO;qBACJ,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACd,MAAM,CAAC,IAAI,KAAK,QAAQ;oBACtB,CAAC,CAAC,MAAM,CAAC,IAAI;oBACb,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CACpC;qBACA,IAAI,CAAC,EAAE,CAAC,CACZ,CAAC;gBACF,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;oBAClC,cAAc,EAAE,KAAK,CAAC,SAAS;oBAC/B,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBACH,MAAM,MAAM,GAAqC,KAAK,EAAE,aAAa;oBACnE,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC;wBAClB,OAAO,EAAE,KAAK,CAAC,aAAa;wBAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;qBACrB,CAAC;oBACJ,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC5B,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,CAAC,EAAE,CAAC;oBACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;oBACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;wBACxC,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,YAAY,EAAE,KAAK,CAAC,YAAY;wBAChC,IAAI,EAAE,IAAI;wBACV,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,cAAc,EAAE,KAAK,CAAC,SAAS;wBAC/B,eAAe,EAAE,UAAU,CAAC,QAAQ,CAAC;6BAClC,MAAM,CACL,IAAI,CAAC,SAAS,CAAC;4BACb,cAAc;4BACd,KAAK,CAAC,IAAI;4BACV,KAAK,CAAC,YAAY;4BAClB,OAAO;yBACR,CAAC,CACH;6BACA,MAAM,CAAC,KAAK,CAAC;wBAChB,IAAI,EAAE,KAAK,IAAI,EAAE;4BACf,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;4BAC7C,OAAO,qBAAqB,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE;gCACjD,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa;gCACxC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gCAClC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;6BAClD,CAAC,CAAC;wBACL,CAAC;qBACF,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC7B,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC;oBACvC,OAAO,EAAE,MAAM,CAAC,EAAE;oBAClB,YAAY,EAAE,MAAM,CAAC,IAAI;oBACzB,OAAO;oBACP,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;oBACjE,cAAc,EAAE,KAAK,CAAC,SAAS;oBAC/B,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBACH,0FAA0F;gBAC1F,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;oBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK,CACT,KAA2D;QAE3D,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACvC,cAAc,EAAE,KAAK,CAAC,SAAS;YAC/B,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;QACH,IAAI,MAAM,GAAqC,KAAK,EAAE,aAAa;YACjE,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACvB,OAAO,EAAE,KAAK,CAAC,aAAa;gBAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CAAC;YACJ,CAAC,CAAC,IAAI,CAAC;QACT,IAAI,YAAY,GAAG,KAAK,EAAE,YAAY,IAAI,SAAS,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACxC,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;gBACrC,IAAI,MAAM;oBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;wBAAE,MAAM,KAAK,CAAC;gBACxE,CAAC;YACH,CAAC;iBAAM,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACpD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,YAAY;oBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxD,CAAC;YACD,IAAI,MAAM,EAAE,MAAM,KAAK,WAAW;gBAAE,MAAM,GAAG,IAAI,CAAC;YAClD,YAAY,GAAG,MAAM;gBACnB,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,SAAS,CAAC;gBACpC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;QACzB,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC7C,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,IAAI;YACV,cAAc,EAAE,KAAK,CAAC,SAAS;YAC/B,YAAY,EAAE,YAAY;YAC1B,eAAe,EAAE,UAAU,CAAC,QAAQ,CAAC;iBAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;iBACnE,MAAM,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC;YACrC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,GAAG,CAAC,MAAM;gBACR,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE;gBACzD,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,6FAA6F;IAC7F,KAAK,CAAC,KAAK,CACT,KAAyB;QAEzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACrC,OAAO,EAAE,KAAK,CAAC,YAAY;oBAC3B,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBACH,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;oBAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,OAAO,KAAK,CAAC;YACf,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;oBAAE,MAAM,KAAK,CAAC;gBACtE,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAChD,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CACrC,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YACpB,MAAM,IAAI,YAAY,CACpB,+EAA+E,EAC/E,EAAE,IAAI,EAAE,UAAU,EAAE,CACrB,CAAC;QACJ,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC5B,CAAC;IAED,4FAA4F;IAC5F,KAAK,CAAC,OAAO,CACX,KAAmC;QAEnC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAgC,EAAE,CAAC;QAC/C,IAAI,MAAM,GAAkB,CAAC,CAAC;QAC9B,GAAG,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACxE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM;gBACvD,MAAM,IAAI,YAAY,CAAC,2BAA2B,EAAE;oBAClD,IAAI,EAAE,UAAU;iBACjB,CAAC,CAAC;YACL,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC3B,CAAC,QAAQ,MAAM,KAAK,IAAI,EAAE;QAC1B,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CACvB,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,KAAK,CAAC,aAAa;YACjD,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;YACvB,CAAC,CAAC,EAAE,CACP,CACF,CAAC;QACF,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,KAAK,EAAE,EAAE,CACR,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;YACzC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAC9B,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,IAAI,CAChB,KAGC,EACD,IAAuB;QAEvB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QACjC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAyB,EAAE,CAAC;QACvC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA8B,CAAC;QAC1D,IAAI,MAAM,GAAkB,CAAC,CAAC;QAC9B,GAAG,CAAC;YACF,MAAM,IAAI,GACR,IAAI,KAAK,MAAM;gBACb,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;gBACrD,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;oBACtB,GAAG,KAAK;oBACR,KAAK,EAAE,KAAK,CAAC,KAAM;oBACnB,MAAM,EAAE,MAAM;iBACf,CAAC,CAAC;YACT,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;gBAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClE,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM;gBACvD,MAAM,IAAI,YAAY,CAAC,6BAA6B,EAAE;oBACpD,IAAI,EAAE,UAAU;iBACjB,CAAC,CAAC;YACL,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC3B,CAAC,QAAQ,MAAM,KAAK,IAAI,EAAE;QAC1B,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvD,KAAK,CAAC,IAAI,CACR,GAAG,OAAO;aACP,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAChB,IAAI,KAAK,QAAQ;YACf,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAM,CAAC,WAAW,EAAE,CAAC;YAC/D,CAAC,CAAC,CAAC,SAAS;gBACV,SAAS,KAAK,GAAG;gBACjB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,SAAS,GAAG,CAAC,CAC3C;aACA,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACf,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC9B,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;SACvB,CAAC,CAAC,CACN,CAAC;QACF,KAAK,CAAC,IAAI,CACR,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CACvE,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC;QACpD,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;YAChC,UAAU,EAAE,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;SAC9C,CAAC;IACJ,CAAC;IACO,KAAK,CACX,KAAQ,EACR,KAAuC;QAEvC,IAAI,KAAK,EAAE,MAAM,KAAK,WAAW;YAAE,OAAO,KAAK,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;YAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvE,OAAO,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvD,CAAC;IACO,MAAM,CACZ,KAAgC;QAEhC,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;YAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACO,OAAO,CAAC,KAAgC;QAC9C,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,EAAE;YAChB,IAAI,EAAE,KAAK,CAAC,EAAE;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,0BAA0B;YACnE,SAAS,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAC9D,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACO,SAAS,CAAC,IAAY;QAC5B,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/B,MAAM,IAAI,YAAY,CAAC,iCAAiC,EAAE;gBACxD,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;QACL,IACE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU;YACzC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa;YAE/B,MAAM,IAAI,YAAY,CAAC,wCAAwC,EAAE;gBAC/D,IAAI,EAAE,gBAAgB;aACvB,CAAC,CAAC;IACP,CAAC;IACO,YAAY;QAClB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IACjD,CAAC;IACO,MAAM;QACZ,MAAM,IAAI,YAAY,CAAC,0CAA0C,EAAE;YACjE,IAAI,EAAE,cAAc;SACrB,CAAC,CAAC;IACL,CAAC;IACO,QAAQ;QACd,MAAM,IAAI,YAAY,CACpB,0EAA0E,EAC1E,EAAE,IAAI,EAAE,UAAU,EAAE,CACrB,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { createHash } from 'node:crypto';\nimport { StorageError, isStorageError } from '../storage.error.js';\nimport { storageBytesStream, storageInteger } from '../core/storage-streams.js';\nimport { editStorageTextStream } from '../core/storage-text-stream-edit.js';\nimport type {\n StorageFileCatalogCapability,\n StorageCatalogFile,\n StorageCatalogPath,\n StorageCatalogCommand,\n StorageCatalogPage,\n} from './storage-file-catalog.types.js';\nimport type {\n StorageFileDraft,\n StorageFileWorkflowCapability,\n StorageFileWorkflowOperation,\n StorageFileWorkflowPage,\n} from './storage-file-workflow.types.js';\n\nexport interface StorageWorkingFile extends StorageCatalogFile {\n readonly operation: 'created' | 'updated';\n readonly pending: true;\n}\nexport interface StorageWorkingFileReceipt {\n readonly path: string;\n readonly etag: string;\n readonly size: number;\n}\n\n/** A path-based editing view over durable checkpoints. Saved heads change only on commit. */\nexport class StorageWorkingFiles<Receipt extends StorageWorkingFileReceipt> {\n readonly catalog: StorageFileCatalogCapability<Receipt | StorageWorkingFile>;\n constructor(\n readonly files: StorageFileCatalogCapability<Receipt>,\n readonly workflow: StorageFileWorkflowCapability<Receipt>,\n ) {\n this.catalog = Object.freeze<\n StorageFileCatalogCapability<Receipt | StorageWorkingFile>\n >({\n ...files,\n list: (input) => this.page(input, 'list'),\n search: (input) => this.page(input, 'search'),\n stat: async (input) => {\n const draft = await this.draft(input);\n return draft && draft.status !== 'committed'\n ? this.receipt(draft)\n : files.stat(this.saved(input, draft));\n },\n readWindow: async (input) => {\n const draft = await this.draft(input);\n if (!draft || draft.status === 'committed')\n return files.readWindow(this.saved(input, draft));\n const page = await workflow.read({\n draftId: draft.id,\n offset: input.offset,\n signal: input.signal,\n });\n if (page.size !== draft.size) this.conflict();\n return {\n ...this.receipt(draft),\n content: page.content,\n offset: page.offset,\n nextOffset: page.nextOffset,\n totalBytes: page.size,\n };\n },\n readStream: async (input) => {\n const draft = await this.draft(input);\n if (!draft || draft.status === 'committed')\n return files.readStream(this.saved(input, draft));\n const stream = await workflow.readStream({\n draftId: draft.id,\n expectedSize: draft.size,\n start: input.start,\n end: input.end,\n signal: input.signal,\n });\n return { ...this.receipt(draft), body: stream.body };\n },\n searchContent: async (input) => {\n const draft = await this.draft(input);\n if (!draft || draft.status === 'committed')\n return files.searchContent(this.saved(input, draft));\n return workflow.searchText({\n draftId: draft.id,\n expectedSize: draft.size,\n query: input.query,\n offset: input.offset,\n signal: input.signal,\n });\n },\n write: (input) => this.write(input),\n edit: async (input) => {\n this.requireWrite();\n const changes =\n input.change.kind === 'batch' ? input.change.changes : [input.change];\n this.textLimit(\n changes\n .map((change) =>\n change.kind === 'append'\n ? change.text\n : change.oldText + change.newText,\n )\n .join(''),\n );\n const prior = await workflow.lookup({\n idempotencyKey: input.commandId,\n signal: input.signal,\n });\n const source: StorageFileDraft<Receipt> | null = prior?.sourceDraftId\n ? await workflow.read({\n draftId: prior.sourceDraftId,\n signal: input.signal,\n })\n : await this.draft(input);\n if (!source || (!prior && source.status === 'committed')) {\n const saved = this.saved(input, source);\n const result = await workflow.stageStream({\n path: input.path,\n expectedEtag: saved.expectedEtag,\n text: true,\n signal: input.signal,\n idempotencyKey: input.commandId,\n contentIdentity: createHash('sha256')\n .update(\n JSON.stringify([\n 'catalog-edit',\n input.path,\n input.expectedEtag,\n changes,\n ]),\n )\n .digest('hex'),\n body: async () => {\n const stream = await files.readStream(saved);\n return editStorageTextStream(stream.body, changes, {\n maxEditBytes: files.limits.maxWriteBytes,\n maxEdits: workflow.limits.maxEdits,\n ...(input.signal ? { signal: input.signal } : {}),\n });\n },\n });\n return this.result(result);\n }\n const result = await workflow.reviseText({\n draftId: source.id,\n expectedSize: source.size,\n changes,\n requestIdentity: JSON.stringify([input.path, input.expectedEtag]),\n idempotencyKey: input.commandId,\n signal: input.signal,\n });\n // The workflow fingerprint includes the source, but the host also fences its public path.\n if (result.path !== input.path) this.conflict();\n return this.result(result);\n },\n });\n }\n\n async write(\n input: StorageCatalogCommand & { readonly content: string },\n ): Promise<Receipt | StorageWorkingFile> {\n this.requireWrite();\n this.textLimit(input.content);\n const prior = await this.workflow.lookup({\n idempotencyKey: input.commandId,\n signal: input.signal,\n });\n let source: StorageFileDraft<Receipt> | null = prior?.sourceDraftId\n ? await this.workflow.read({\n draftId: prior.sourceDraftId,\n signal: input.signal,\n })\n : null;\n let originalEtag = prior?.expectedEtag ?? undefined;\n if (!prior) {\n source = await this.draft(input);\n const saved = this.saved(input, source);\n if (input.expectedEtag === undefined) {\n if (source) this.conflict();\n try {\n await this.files.stat(input);\n this.conflict();\n } catch (error) {\n if (!isStorageError(error) || error.code !== 'NOT_FOUND') throw error;\n }\n } else if (!source || source.status === 'committed') {\n const file = await this.files.stat(saved);\n if (file.etag !== saved.expectedEtag) this.conflict();\n }\n if (source?.status === 'committed') source = null;\n originalEtag = source\n ? (source.expectedEtag ?? undefined)\n : saved.expectedEtag;\n }\n const bytes = new TextEncoder().encode(input.content);\n const result = await this.workflow.stageStream({\n path: input.path,\n text: true,\n idempotencyKey: input.commandId,\n expectedEtag: originalEtag,\n contentIdentity: createHash('sha256')\n .update(JSON.stringify([input.expectedEtag ?? null, input.content]))\n .digest('hex'),\n body: () => storageBytesStream(bytes),\n signal: input.signal,\n ...(source\n ? { sourceDraftId: source.id, expectedSize: source.size }\n : {}),\n });\n return this.result(result);\n }\n\n /** Resolve an exact candidate (including committed replay) or the unique unfinished leaf. */\n async draft(\n input: StorageCatalogPath,\n ): Promise<StorageFileDraft<Receipt> | null> {\n if (!this.files.allows('read')) this.denied();\n if (input.expectedEtag !== undefined) {\n try {\n const draft = await this.workflow.read({\n draftId: input.expectedEtag,\n signal: input.signal,\n });\n if (draft.path !== input.path || draft.status === 'cancelled')\n this.conflict();\n return draft;\n } catch (error) {\n if (!isStorageError(error) || error.code !== 'NOT_FOUND') throw error;\n return null;\n }\n }\n const matches = (await this.pending(input)).filter(\n (draft) => draft.path === input.path,\n );\n if (matches.length > 1)\n throw new StorageError(\n 'Several unfinished revisions exist. Read an exact listed ETag before editing.',\n { code: 'CONFLICT' },\n );\n return matches[0] ?? null;\n }\n\n /** Discovery derives from persisted lineage, so process restarts need no local registry. */\n async pending(\n input: StorageFileWorkflowOperation,\n ): Promise<StorageFileDraft<Receipt>[]> {\n if (!this.files.allows('read')) this.denied();\n const drafts: StorageFileDraft<Receipt>[] = [];\n let offset: number | null = 0;\n do {\n const page = await this.workflow.list({ offset, signal: input.signal });\n drafts.push(...page.items);\n if (page.nextOffset !== null && page.nextOffset <= offset)\n throw new StorageError('Invalid draft pagination.', {\n code: 'PROVIDER',\n });\n offset = page.nextOffset;\n } while (offset !== null);\n const predecessors = new Set(\n drafts.flatMap((draft) =>\n draft.status !== 'cancelled' && draft.sourceDraftId\n ? [draft.sourceDraftId]\n : [],\n ),\n );\n return drafts.filter(\n (draft) =>\n ['open', 'sealed'].includes(draft.status) &&\n !predecessors.has(draft.id),\n );\n }\n\n private async page(\n input: StorageCatalogPage & {\n directory?: string | undefined;\n query?: string;\n },\n mode: 'list' | 'search',\n ) {\n const offset = input.offset ?? 0;\n storageInteger(offset, 'offset', 0);\n const pending = await this.pending(input);\n const paths = new Set(pending.map((draft) => draft.path));\n const items: StorageCatalogFile[] = [];\n const savedByPath = new Map<string, StorageCatalogFile>();\n let cursor: number | null = 0;\n do {\n const page: StorageFileWorkflowPage<StorageCatalogFile> =\n mode === 'list'\n ? await this.files.list({ ...input, offset: cursor })\n : await this.files.search({\n ...input,\n query: input.query!,\n offset: cursor,\n });\n for (const file of page.items) savedByPath.set(file.path, file);\n items.push(...page.items.filter((file) => !paths.has(file.path)));\n if (page.nextOffset !== null && page.nextOffset <= cursor)\n throw new StorageError('Invalid catalog pagination.', {\n code: 'PROVIDER',\n });\n cursor = page.nextOffset;\n } while (cursor !== null);\n const directory = input.directory?.replace(/\\/$/u, '');\n items.push(\n ...pending\n .filter((draft) =>\n mode === 'search'\n ? draft.path.toLowerCase().includes(input.query!.toLowerCase())\n : !directory ||\n directory === '.' ||\n draft.path.startsWith(`${directory}/`),\n )\n .map((draft) => ({\n ...savedByPath.get(draft.path),\n ...this.receipt(draft),\n })),\n );\n items.sort(\n (a, b) => a.path.localeCompare(b.path) || a.etag.localeCompare(b.etag),\n );\n const next = offset + this.files.limits.maxPageSize;\n return {\n items: items.slice(offset, next),\n nextOffset: next < items.length ? next : null,\n };\n }\n private saved<T extends StorageCatalogPath>(\n input: T,\n draft: StorageFileDraft<Receipt> | null,\n ): T {\n if (draft?.status !== 'committed') return input;\n if (!draft.result || draft.result.path !== input.path) this.conflict();\n return { ...input, expectedEtag: draft.result.etag };\n }\n private result(\n draft: StorageFileDraft<Receipt>,\n ): Receipt | StorageWorkingFile {\n if (draft.status === 'cancelled') this.conflict();\n if (draft.status === 'committed') {\n if (!draft.result) this.conflict();\n return draft.result;\n }\n return this.receipt(draft);\n }\n private receipt(draft: StorageFileDraft<Receipt>): StorageWorkingFile {\n return {\n path: draft.path,\n fileId: draft.id,\n etag: draft.id,\n size: draft.size,\n contentType: draft.text ? 'text/plain' : 'application/octet-stream',\n operation: draft.expectedEtag === null ? 'created' : 'updated',\n pending: true,\n };\n }\n private textLimit(text: string) {\n if (/[\\uD800-\\uDFFF]/u.test(text))\n throw new StorageError('Text must be well-formed UTF-8.', {\n code: 'INVALID_ARGUMENT',\n });\n if (\n new TextEncoder().encode(text).byteLength >\n this.files.limits.maxWriteBytes\n )\n throw new StorageError('Write exceeds the per-call text limit.', {\n code: 'LIMIT_EXCEEDED',\n });\n }\n private requireWrite() {\n if (!this.files.allows('write')) this.denied();\n }\n private denied(): never {\n throw new StorageError('Working file operation is not permitted.', {\n code: 'UNAUTHORIZED',\n });\n }\n private conflict(): never {\n throw new StorageError(\n 'The working file revision changed. Read the current file before editing.',\n { code: 'CONFLICT' },\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { StorageWorkspaceLimits, StorageWorkspaceSearchMatch } from './storage-workspace.types.js';
|
|
2
|
+
export declare const STORAGE_WORKSPACE_CURSOR_VERSION: 1;
|
|
3
|
+
export declare const STORAGE_WORKSPACE_MAX_CURSOR_BYTES = 4096;
|
|
4
|
+
export interface StorageWorkspaceCursorEncodeOptions {
|
|
5
|
+
/** Absolute Unix timestamp in milliseconds used by durable stores for TTL. */
|
|
6
|
+
readonly expiresAt: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Server-side opaque cursor contract. Implementations must either authenticate
|
|
10
|
+
* and encrypt payloads or keep them behind a shared durable random token.
|
|
11
|
+
* Tokens use only `[A-Za-z0-9._-]`, are at most 4,096 bytes, and `decode` must
|
|
12
|
+
* be non-destructive so the same token remains replayable until its authenticated
|
|
13
|
+
* expiry. Durable stores must expire records at `options.expiresAt` and read
|
|
14
|
+
* rather than consume them. Missing or expired records should fail with
|
|
15
|
+
* `StorageErrorCode.NOT_FOUND` or `StorageErrorCode.INVALID_ARGUMENT`;
|
|
16
|
+
* availability failures retain their operational storage error code.
|
|
17
|
+
*/
|
|
18
|
+
export interface StorageWorkspaceCursorCodec {
|
|
19
|
+
encode(payload: Uint8Array, options: StorageWorkspaceCursorEncodeOptions): Promise<string> | string;
|
|
20
|
+
decode(token: string): Promise<Uint8Array> | Uint8Array;
|
|
21
|
+
}
|
|
22
|
+
export interface StorageWorkspaceCursorConfiguration {
|
|
23
|
+
/** Codec shared by every replica that serves this logical mount. */
|
|
24
|
+
readonly codec: StorageWorkspaceCursorCodec;
|
|
25
|
+
/** Stable server-derived mount or binding identity. */
|
|
26
|
+
readonly mountId: string;
|
|
27
|
+
/** Stable trusted tenant/workspace scope. */
|
|
28
|
+
readonly scope: string;
|
|
29
|
+
}
|
|
30
|
+
export interface Aes256GcmStorageWorkspaceCursorCodecOptions {
|
|
31
|
+
/** Key used for newly issued cursors. */
|
|
32
|
+
readonly activeKeyId: string;
|
|
33
|
+
/** Decryption key ring. Retain rotated keys for at least one cursor TTL. */
|
|
34
|
+
readonly keys: Readonly<Record<string, Uint8Array>>;
|
|
35
|
+
}
|
|
36
|
+
/** Stateless AES-256-GCM cursor codec suitable for shared multi-replica use. */
|
|
37
|
+
export declare class Aes256GcmStorageWorkspaceCursorCodec implements StorageWorkspaceCursorCodec {
|
|
38
|
+
#private;
|
|
39
|
+
constructor(options: Aes256GcmStorageWorkspaceCursorCodecOptions);
|
|
40
|
+
encode(payload: Uint8Array, options: StorageWorkspaceCursorEncodeOptions): string;
|
|
41
|
+
decode(token: string): Uint8Array;
|
|
42
|
+
}
|
|
43
|
+
interface StorageWorkspaceCursorBinding {
|
|
44
|
+
readonly limits: Readonly<StorageWorkspaceLimits>;
|
|
45
|
+
readonly prefix: string;
|
|
46
|
+
readonly store: string;
|
|
47
|
+
}
|
|
48
|
+
export interface StorageWorkspaceListCursorData {
|
|
49
|
+
readonly backendCursor: string;
|
|
50
|
+
readonly directory: string;
|
|
51
|
+
readonly limit: number;
|
|
52
|
+
readonly operation: 'list';
|
|
53
|
+
readonly recursive: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface StorageWorkspaceSearchCursorData {
|
|
56
|
+
readonly backendCursor: string;
|
|
57
|
+
readonly caseInsensitive: boolean;
|
|
58
|
+
readonly directory: string;
|
|
59
|
+
readonly limit: number;
|
|
60
|
+
readonly match: StorageWorkspaceSearchMatch;
|
|
61
|
+
readonly operation: 'search';
|
|
62
|
+
readonly query: string;
|
|
63
|
+
readonly scanned: number;
|
|
64
|
+
}
|
|
65
|
+
export type StorageWorkspaceCursorData = StorageWorkspaceListCursorData | StorageWorkspaceSearchCursorData;
|
|
66
|
+
export declare function resolveStorageWorkspaceCursorConfiguration(configuration: StorageWorkspaceCursorConfiguration | undefined): Readonly<StorageWorkspaceCursorConfiguration> | undefined;
|
|
67
|
+
export declare function issueStorageWorkspaceCursor(configuration: Readonly<StorageWorkspaceCursorConfiguration> | undefined, binding: StorageWorkspaceCursorBinding, cursor: StorageWorkspaceCursorData): Promise<string>;
|
|
68
|
+
export declare function decodeStorageWorkspaceCursor(configuration: Readonly<StorageWorkspaceCursorConfiguration> | undefined, binding: StorageWorkspaceCursorBinding, operation: 'list', token: string): Promise<StorageWorkspaceListCursorData>;
|
|
69
|
+
export declare function decodeStorageWorkspaceCursor(configuration: Readonly<StorageWorkspaceCursorConfiguration> | undefined, binding: StorageWorkspaceCursorBinding, operation: 'search', token: string): Promise<StorageWorkspaceSearchCursorData>;
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=storage-workspace.cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-workspace.cursor.d.ts","sourceRoot":"","sources":["../../src/workspace/storage-workspace.cursor.ts"],"names":[],"mappings":"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"}
|