@nestm/storage 0.1.0-alpha.17 → 0.1.0-alpha.18
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 +6 -0
- package/README.md +21 -1
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts +2 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts.map +1 -1
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.js +19 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.js.map +1 -1
- package/dist/ai-sdk/index.d.ts +1 -1
- package/dist/ai-sdk/index.d.ts.map +1 -1
- package/dist/ai-sdk/index.js +1 -1
- package/dist/ai-sdk/index.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- 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/files-sdk/provider/index.d.ts.map +1 -1
- package/dist/files-sdk/provider/index.js +14 -0
- package/dist/files-sdk/provider/index.js.map +1 -1
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +1 -0
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/storage-catalog-checkout.d.ts +1 -1
- package/dist/workspace/storage-catalog-checkout.d.ts.map +1 -1
- package/dist/workspace/storage-catalog-checkout.js +49 -35
- package/dist/workspace/storage-catalog-checkout.js.map +1 -1
- 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-workflow.d.ts.map +1 -1
- package/dist/workspace/storage-file-workflow.js +96 -10
- package/dist/workspace/storage-file-workflow.js.map +1 -1
- package/dist/workspace/storage-file-workflow.protection.d.ts.map +1 -1
- package/dist/workspace/storage-file-workflow.protection.js +10 -0
- package/dist/workspace/storage-file-workflow.protection.js.map +1 -1
- package/dist/workspace/storage-file-workflow.types.d.ts +25 -1
- package/dist/workspace/storage-file-workflow.types.d.ts.map +1 -1
- package/dist/workspace/storage-file-workflow.types.js.map +1 -1
- package/dist/workspace/storage-text-draft.d.ts +2 -1
- package/dist/workspace/storage-text-draft.d.ts.map +1 -1
- package/dist/workspace/storage-text-draft.js +15 -18
- package/dist/workspace/storage-text-draft.js.map +1 -1
- 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 +291 -0
- package/dist/workspace/storage-working-files.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oCAAoC,EAAE,MAAM,kCAAkC,CAAC;AACxF,mBAAmB,kCAAkC,CAAC;AACtD,mBAAmB,iCAAiC,CAAC;AACrD,OAAO,EACL,mCAAmC,EACnC,mCAAmC,EACnC,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EACjC,KAAK,0CAA0C,GAChD,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,oCAAoC,EACpC,gCAAgC,EAChC,kCAAkC,EAClC,KAAK,2CAA2C,EAChD,KAAK,2BAA2B,EAChC,KAAK,mCAAmC,EACxC,KAAK,mCAAmC,GACzC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gCAAgC,EAChC,6BAA6B,EAC7B,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,0CAA0C,EAC/C,KAAK,4BAA4B,GAClC,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oCAAoC,EAAE,MAAM,kCAAkC,CAAC;AACxF,mBAAmB,kCAAkC,CAAC;AACtD,mBAAmB,iCAAiC,CAAC;AACrD,OAAO,EACL,mCAAmC,EACnC,mCAAmC,EACnC,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EACjC,KAAK,0CAA0C,GAChD,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,oCAAoC,EACpC,gCAAgC,EAChC,kCAAkC,EAClC,KAAK,2CAA2C,EAChD,KAAK,2BAA2B,EAChC,KAAK,mCAAmC,EACxC,KAAK,mCAAmC,GACzC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gCAAgC,EAChC,6BAA6B,EAC7B,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,0CAA0C,EAC/C,KAAK,4BAA4B,GAClC,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAE3E,OAAO,EACL,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,4BAA4B,CAAC"}
|
package/dist/workspace/index.js
CHANGED
|
@@ -6,4 +6,5 @@ export { Aes256GcmStorageWorkspaceCursorCodec, STORAGE_WORKSPACE_CURSOR_VERSION,
|
|
|
6
6
|
export { createStorageWorkspace, mountStorageWorkspace, } from './storage-workspace.js';
|
|
7
7
|
export { DEFAULT_STORAGE_WORKSPACE_LIMITS, STORAGE_WORKSPACE_PERMISSIONS, } from './storage-workspace.types.js';
|
|
8
8
|
export { checkoutStorageCatalogText } from './storage-catalog-checkout.js';
|
|
9
|
+
export { StorageWorkingFiles, } from './storage-working-files.js';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oCAAoC,EAAE,MAAM,kCAAkC,CAAC;AAGxF,OAAO,EACL,mCAAmC,EACnC,mCAAmC,EACnC,sBAAsB,EACtB,qBAAqB,GAItB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,oCAAoC,EACpC,gCAAgC,EAChC,kCAAkC,GAKnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gCAAgC,EAChC,6BAA6B,GAuB9B,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC","sourcesContent":["export {\n StorageWorkspaceError,\n isStorageWorkspaceError,\n} from './storage-workspace.error.js';\nexport { StorageFileWorkflow } from './storage-file-workflow.js';\nexport { DEFAULT_STORAGE_FILE_WORKFLOW_LIMITS } from './storage-file-workflow.types.js';\nexport type * from './storage-file-workflow.types.js';\nexport type * from './storage-file-catalog.types.js';\nexport {\n protectStorageFileWorkflowWorkspace,\n protectStorageFileWorkflowOperation,\n getStorageFileWorkflow,\n getStorageFileCatalog,\n type StorageFileWorkflowProtection,\n type StorageFileWorkflowWorkspace,\n type ProtectStorageFileWorkflowWorkspaceOptions,\n} from './storage-file-workflow.protection.js';\nexport {\n Aes256GcmStorageWorkspaceCursorCodec,\n STORAGE_WORKSPACE_CURSOR_VERSION,\n STORAGE_WORKSPACE_MAX_CURSOR_BYTES,\n type Aes256GcmStorageWorkspaceCursorCodecOptions,\n type StorageWorkspaceCursorCodec,\n type StorageWorkspaceCursorConfiguration,\n type StorageWorkspaceCursorEncodeOptions,\n} from './storage-workspace.cursor.js';\nexport {\n createStorageWorkspace,\n mountStorageWorkspace,\n} from './storage-workspace.js';\nexport {\n DEFAULT_STORAGE_WORKSPACE_LIMITS,\n STORAGE_WORKSPACE_PERMISSIONS,\n type MountStorageWorkspaceOptions,\n type StorageWorkspaceBody,\n type StorageWorkspaceByteFile,\n type StorageWorkspaceCopyOptions,\n type StorageWorkspaceDeleteOptions,\n type StorageWorkspace,\n type StorageWorkspaceDirectory,\n type StorageWorkspaceEntry,\n type StorageWorkspaceFile,\n type StorageWorkspaceLimits,\n type StorageWorkspaceListOptions,\n type StorageWorkspaceMountOptions,\n type StorageWorkspaceMutationOptions,\n type StorageWorkspaceOverwriteOptions,\n type StorageWorkspacePage,\n type StorageWorkspacePermission,\n type StorageWorkspaceReadOptions,\n type StorageWorkspaceSearchMatch,\n type StorageWorkspaceSearchOptions,\n type StorageWorkspaceTextFile,\n type StorageWorkspaceUnconditionalDeleteOptions,\n type StorageWorkspaceWriteOptions,\n} from './storage-workspace.types.js';\n\nexport { checkoutStorageCatalogText } from './storage-catalog-checkout.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oCAAoC,EAAE,MAAM,kCAAkC,CAAC;AAGxF,OAAO,EACL,mCAAmC,EACnC,mCAAmC,EACnC,sBAAsB,EACtB,qBAAqB,GAItB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,oCAAoC,EACpC,gCAAgC,EAChC,kCAAkC,GAKnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gCAAgC,EAChC,6BAA6B,GAuB9B,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAE3E,OAAO,EACL,mBAAmB,GAEpB,MAAM,4BAA4B,CAAC","sourcesContent":["export {\n StorageWorkspaceError,\n isStorageWorkspaceError,\n} from './storage-workspace.error.js';\nexport { StorageFileWorkflow } from './storage-file-workflow.js';\nexport { DEFAULT_STORAGE_FILE_WORKFLOW_LIMITS } from './storage-file-workflow.types.js';\nexport type * from './storage-file-workflow.types.js';\nexport type * from './storage-file-catalog.types.js';\nexport {\n protectStorageFileWorkflowWorkspace,\n protectStorageFileWorkflowOperation,\n getStorageFileWorkflow,\n getStorageFileCatalog,\n type StorageFileWorkflowProtection,\n type StorageFileWorkflowWorkspace,\n type ProtectStorageFileWorkflowWorkspaceOptions,\n} from './storage-file-workflow.protection.js';\nexport {\n Aes256GcmStorageWorkspaceCursorCodec,\n STORAGE_WORKSPACE_CURSOR_VERSION,\n STORAGE_WORKSPACE_MAX_CURSOR_BYTES,\n type Aes256GcmStorageWorkspaceCursorCodecOptions,\n type StorageWorkspaceCursorCodec,\n type StorageWorkspaceCursorConfiguration,\n type StorageWorkspaceCursorEncodeOptions,\n} from './storage-workspace.cursor.js';\nexport {\n createStorageWorkspace,\n mountStorageWorkspace,\n} from './storage-workspace.js';\nexport {\n DEFAULT_STORAGE_WORKSPACE_LIMITS,\n STORAGE_WORKSPACE_PERMISSIONS,\n type MountStorageWorkspaceOptions,\n type StorageWorkspaceBody,\n type StorageWorkspaceByteFile,\n type StorageWorkspaceCopyOptions,\n type StorageWorkspaceDeleteOptions,\n type StorageWorkspace,\n type StorageWorkspaceDirectory,\n type StorageWorkspaceEntry,\n type StorageWorkspaceFile,\n type StorageWorkspaceLimits,\n type StorageWorkspaceListOptions,\n type StorageWorkspaceMountOptions,\n type StorageWorkspaceMutationOptions,\n type StorageWorkspaceOverwriteOptions,\n type StorageWorkspacePage,\n type StorageWorkspacePermission,\n type StorageWorkspaceReadOptions,\n type StorageWorkspaceSearchMatch,\n type StorageWorkspaceSearchOptions,\n type StorageWorkspaceTextFile,\n type StorageWorkspaceUnconditionalDeleteOptions,\n type StorageWorkspaceWriteOptions,\n} from './storage-workspace.types.js';\n\nexport { checkoutStorageCatalogText } from './storage-catalog-checkout.js';\n\nexport {\n StorageWorkingFiles,\n type StorageWorkingFile,\n} from './storage-working-files.js';\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StorageFileCatalogCapability, StorageCatalogCommand } from './storage-file-catalog.types.js';
|
|
2
2
|
import type { StorageFileWorkflowCapability } from './storage-file-workflow.types.js';
|
|
3
|
-
/**
|
|
3
|
+
/** Stream exact catalog windows into a sealed checkpoint without buffering the file. */
|
|
4
4
|
export declare function checkoutStorageCatalogText<Receipt>(catalog: StorageFileCatalogCapability<Receipt>, workflow: StorageFileWorkflowCapability<Receipt>, input: StorageCatalogCommand & {
|
|
5
5
|
readonly expectedEtag: string;
|
|
6
6
|
}): Promise<import("./storage-file-workflow.types.js").StorageFileDraft<Receipt>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-catalog-checkout.d.ts","sourceRoot":"","sources":["../../src/workspace/storage-catalog-checkout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAEtF,
|
|
1
|
+
{"version":3,"file":"storage-catalog-checkout.d.ts","sourceRoot":"","sources":["../../src/workspace/storage-catalog-checkout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAEtF,wFAAwF;AACxF,wBAAsB,0BAA0B,CAAC,OAAO,EACtD,OAAO,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAC9C,QAAQ,EAAE,6BAA6B,CAAC,OAAO,CAAC,EAChD,KAAK,EAAE,qBAAqB,GAAG;IAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,iFAkEjE"}
|
|
@@ -1,46 +1,60 @@
|
|
|
1
1
|
import { StorageError } from '../storage.error.js';
|
|
2
|
-
/**
|
|
2
|
+
/** Stream exact catalog windows into a sealed checkpoint without buffering the file. */
|
|
3
3
|
export async function checkoutStorageCatalogText(catalog, workflow, input) {
|
|
4
4
|
const file = await catalog.stat(input);
|
|
5
5
|
if (file.etag !== input.expectedEtag)
|
|
6
6
|
throw new StorageError('The catalog revision changed.', {
|
|
7
7
|
code: 'CONFLICT',
|
|
8
8
|
});
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let offset = 0;
|
|
15
|
-
do {
|
|
16
|
-
const page = await catalog.readWindow({ ...input, offset });
|
|
17
|
-
if (page.etag !== input.expectedEtag ||
|
|
18
|
-
page.totalBytes !== file.size ||
|
|
19
|
-
page.offset !== offset)
|
|
20
|
-
throw new StorageError('The catalog revision changed.', {
|
|
21
|
-
code: 'CONFLICT',
|
|
22
|
-
});
|
|
23
|
-
if (page.content === null)
|
|
24
|
-
throw new StorageError('Checkout requires a text file.', {
|
|
25
|
-
code: 'INVALID_ARGUMENT',
|
|
26
|
-
});
|
|
27
|
-
const next = offset + new TextEncoder().encode(page.content).byteLength;
|
|
28
|
-
if (next > file.size ||
|
|
29
|
-
(page.nextOffset === null
|
|
30
|
-
? next !== file.size
|
|
31
|
-
: page.nextOffset !== next || next <= offset))
|
|
32
|
-
throw new StorageError('Invalid catalog text window.', {
|
|
33
|
-
code: 'PROVIDER',
|
|
34
|
-
});
|
|
35
|
-
pieces.push(page.content);
|
|
36
|
-
offset = next;
|
|
37
|
-
if (page.nextOffset === null)
|
|
38
|
-
break;
|
|
39
|
-
} while (offset < file.size);
|
|
40
|
-
return workflow.stageText({
|
|
41
|
-
...input,
|
|
42
|
-
content: pieces.join(''),
|
|
9
|
+
return workflow.stageStream({
|
|
10
|
+
path: input.path,
|
|
11
|
+
expectedEtag: input.expectedEtag,
|
|
12
|
+
text: true,
|
|
13
|
+
signal: input.signal,
|
|
43
14
|
idempotencyKey: input.commandId,
|
|
15
|
+
contentIdentity: JSON.stringify([file.fileId, file.etag, file.size]),
|
|
16
|
+
body: () => {
|
|
17
|
+
let offset = 0;
|
|
18
|
+
return new ReadableStream({
|
|
19
|
+
async pull(controller) {
|
|
20
|
+
try {
|
|
21
|
+
const page = await catalog.readWindow({ ...input, offset });
|
|
22
|
+
if (page.etag !== input.expectedEtag ||
|
|
23
|
+
page.totalBytes !== file.size ||
|
|
24
|
+
page.offset !== offset)
|
|
25
|
+
throw new StorageError('The catalog revision changed.', {
|
|
26
|
+
code: 'CONFLICT',
|
|
27
|
+
});
|
|
28
|
+
if (page.content === null)
|
|
29
|
+
throw new StorageError('Checkout requires a text file.', {
|
|
30
|
+
code: 'INVALID_ARGUMENT',
|
|
31
|
+
});
|
|
32
|
+
const next = offset + new TextEncoder().encode(page.content).byteLength;
|
|
33
|
+
if (next > file.size ||
|
|
34
|
+
(page.nextOffset === null
|
|
35
|
+
? next !== file.size
|
|
36
|
+
: page.nextOffset !== next || next <= offset))
|
|
37
|
+
throw new StorageError('Invalid catalog text window.', {
|
|
38
|
+
code: 'PROVIDER',
|
|
39
|
+
});
|
|
40
|
+
controller.enqueue(new TextEncoder().encode(page.content));
|
|
41
|
+
offset = next;
|
|
42
|
+
if (page.nextOffset === null) {
|
|
43
|
+
const current = await catalog.stat(input);
|
|
44
|
+
if (current.etag !== input.expectedEtag ||
|
|
45
|
+
current.size !== file.size)
|
|
46
|
+
throw new StorageError('The catalog revision changed.', {
|
|
47
|
+
code: 'CONFLICT',
|
|
48
|
+
});
|
|
49
|
+
controller.close();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
controller.error(error);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
}, { highWaterMark: 0 });
|
|
57
|
+
},
|
|
44
58
|
});
|
|
45
59
|
}
|
|
46
60
|
//# sourceMappingURL=storage-catalog-checkout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-catalog-checkout.js","sourceRoot":"","sources":["../../src/workspace/storage-catalog-checkout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOnD,
|
|
1
|
+
{"version":3,"file":"storage-catalog-checkout.js","sourceRoot":"","sources":["../../src/workspace/storage-catalog-checkout.ts"],"names":[],"mappings":"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","sourcesContent":["import { StorageError } from '../storage.error.js';\nimport type {\n StorageFileCatalogCapability,\n StorageCatalogCommand,\n} from './storage-file-catalog.types.js';\nimport type { StorageFileWorkflowCapability } from './storage-file-workflow.types.js';\n\n/** Stream exact catalog windows into a sealed checkpoint without buffering the file. */\nexport async function checkoutStorageCatalogText<Receipt>(\n catalog: StorageFileCatalogCapability<Receipt>,\n workflow: StorageFileWorkflowCapability<Receipt>,\n input: StorageCatalogCommand & { readonly expectedEtag: string },\n) {\n const file = await catalog.stat(input);\n if (file.etag !== input.expectedEtag)\n throw new StorageError('The catalog revision changed.', {\n code: 'CONFLICT',\n });\n return workflow.stageStream({\n path: input.path,\n expectedEtag: input.expectedEtag,\n text: true,\n signal: input.signal,\n idempotencyKey: input.commandId,\n contentIdentity: JSON.stringify([file.fileId, file.etag, file.size]),\n body: () => {\n let offset = 0;\n return new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n try {\n const page = await catalog.readWindow({ ...input, offset });\n if (\n page.etag !== input.expectedEtag ||\n page.totalBytes !== file.size ||\n page.offset !== offset\n )\n throw new StorageError('The catalog revision changed.', {\n code: 'CONFLICT',\n });\n if (page.content === null)\n throw new StorageError('Checkout requires a text file.', {\n code: 'INVALID_ARGUMENT',\n });\n const next =\n offset + new TextEncoder().encode(page.content).byteLength;\n if (\n next > file.size ||\n (page.nextOffset === null\n ? next !== file.size\n : page.nextOffset !== next || next <= offset)\n )\n throw new StorageError('Invalid catalog text window.', {\n code: 'PROVIDER',\n });\n controller.enqueue(new TextEncoder().encode(page.content));\n offset = next;\n if (page.nextOffset === null) {\n const current = await catalog.stat(input);\n if (\n current.etag !== input.expectedEtag ||\n current.size !== file.size\n )\n throw new StorageError('The catalog revision changed.', {\n code: 'CONFLICT',\n });\n controller.close();\n }\n } catch (error) {\n controller.error(error);\n }\n },\n },\n { highWaterMark: 0 },\n );\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Bounded byte rechunking; each text chunk ends at a complete Unicode scalar. */
|
|
2
|
+
export declare function chunkStorageDraftStream(source: ReadableStream<Uint8Array>, maxBytes: number, text: boolean, signal: AbortSignal): AsyncGenerator<Uint8Array<ArrayBufferLike>, void, unknown>;
|
|
3
|
+
//# sourceMappingURL=storage-draft-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-draft-stream.d.ts","sourceRoot":"","sources":["../../src/workspace/storage-draft-stream.ts"],"names":[],"mappings":"AAGA,kFAAkF;AAClF,wBAAuB,uBAAuB,CAC5C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,WAAW,8DAiDpB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { trimStorageUtf8Chunk } from '../bytes/index.js';
|
|
2
|
+
import { StorageError } from '../storage.error.js';
|
|
3
|
+
/** Bounded byte rechunking; each text chunk ends at a complete Unicode scalar. */
|
|
4
|
+
export async function* chunkStorageDraftStream(source, maxBytes, text, signal) {
|
|
5
|
+
if (maxBytes < (text ? 4 : 1)) {
|
|
6
|
+
await source.cancel().catch(() => { });
|
|
7
|
+
throw new StorageError('Chunk limit is too small.', {
|
|
8
|
+
code: 'LIMIT_EXCEEDED',
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
let buffer = new Uint8Array(maxBytes);
|
|
12
|
+
let filled = 0;
|
|
13
|
+
const reader = source.getReader();
|
|
14
|
+
const abort = () => {
|
|
15
|
+
void reader.cancel(signal.reason).catch(() => { });
|
|
16
|
+
};
|
|
17
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
18
|
+
try {
|
|
19
|
+
signal.throwIfAborted();
|
|
20
|
+
for (;;) {
|
|
21
|
+
const next = await reader.read();
|
|
22
|
+
signal.throwIfAborted();
|
|
23
|
+
if (next.done)
|
|
24
|
+
break;
|
|
25
|
+
for (let at = 0; at < next.value.length;) {
|
|
26
|
+
const count = Math.min(maxBytes - filled, next.value.length - at);
|
|
27
|
+
buffer.set(next.value.subarray(at, at + count), filled);
|
|
28
|
+
filled += count;
|
|
29
|
+
at += count;
|
|
30
|
+
if (filled === maxBytes) {
|
|
31
|
+
const complete = text
|
|
32
|
+
? trimStorageUtf8Chunk(buffer, { final: false })
|
|
33
|
+
: buffer;
|
|
34
|
+
if (text)
|
|
35
|
+
new TextDecoder('utf-8', { fatal: true }).decode(complete);
|
|
36
|
+
yield complete;
|
|
37
|
+
const rest = buffer.subarray(complete.length);
|
|
38
|
+
buffer = new Uint8Array(maxBytes);
|
|
39
|
+
buffer.set(rest);
|
|
40
|
+
filled = rest.length;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (filled) {
|
|
45
|
+
const final = buffer.subarray(0, filled);
|
|
46
|
+
if (text)
|
|
47
|
+
new TextDecoder('utf-8', { fatal: true }).decode(final);
|
|
48
|
+
yield final;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
signal.removeEventListener('abort', abort);
|
|
53
|
+
await reader.cancel().catch(() => { });
|
|
54
|
+
reader.releaseLock();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=storage-draft-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-draft-stream.js","sourceRoot":"","sources":["../../src/workspace/storage-draft-stream.ts"],"names":[],"mappings":"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","sourcesContent":["import { trimStorageUtf8Chunk } from '../bytes/index.js';\nimport { StorageError } from '../storage.error.js';\n\n/** Bounded byte rechunking; each text chunk ends at a complete Unicode scalar. */\nexport async function* chunkStorageDraftStream(\n source: ReadableStream<Uint8Array>,\n maxBytes: number,\n text: boolean,\n signal: AbortSignal,\n) {\n if (maxBytes < (text ? 4 : 1)) {\n await source.cancel().catch(() => {});\n throw new StorageError('Chunk limit is too small.', {\n code: 'LIMIT_EXCEEDED',\n });\n }\n let buffer = new Uint8Array(maxBytes);\n let filled = 0;\n const reader = source.getReader();\n const abort = () => {\n void reader.cancel(signal.reason).catch(() => {});\n };\n signal.addEventListener('abort', abort, { once: true });\n try {\n signal.throwIfAborted();\n for (;;) {\n const next = await reader.read();\n signal.throwIfAborted();\n if (next.done) break;\n for (let at = 0; at < next.value.length;) {\n const count = Math.min(maxBytes - filled, next.value.length - at);\n buffer.set(next.value.subarray(at, at + count), filled);\n filled += count;\n at += count;\n if (filled === maxBytes) {\n const complete = text\n ? trimStorageUtf8Chunk(buffer, { final: false })\n : buffer;\n if (text) new TextDecoder('utf-8', { fatal: true }).decode(complete);\n yield complete;\n const rest = buffer.subarray(complete.length);\n buffer = new Uint8Array(maxBytes);\n buffer.set(rest);\n filled = rest.length;\n }\n }\n }\n if (filled) {\n const final = buffer.subarray(0, filled);\n if (text) new TextDecoder('utf-8', { fatal: true }).decode(final);\n yield final;\n }\n } finally {\n signal.removeEventListener('abort', abort);\n await reader.cancel().catch(() => {});\n reader.releaseLock();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-file-workflow.d.ts","sourceRoot":"","sources":["../../src/workspace/storage-file-workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storage-file-workflow.d.ts","sourceRoot":"","sources":["../../src/workspace/storage-file-workflow.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,KAAK,+BAA+B,EAGpC,KAAK,6BAA6B,EAGlC,KAAK,0BAA0B,EAIhC,MAAM,kCAAkC,CAAC;AAE1C,qBAAa,mBAAmB,CAAC,KAAK,EAAE,OAAO;;IAE7C,YAAY,OAAO,EAAE,0BAA0B,CAAC,KAAK,EAAE,OAAO,CAAC,EAE9D;IAED,KAAK,CACH,KAAK,EAAE,KAAK,EACZ,OAAO,GAAE,+BAAoC,GAC5C,6BAA6B,CAAC,OAAO,CAAC,CAkpBxC;CA6FF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { searchStorageText } from '../core/storage-text.js';
|
|
2
|
+
import { editStorageTextStream } from '../core/storage-text-stream-edit.js';
|
|
2
3
|
import { stageStorageTextDraft } from './storage-text-draft.js';
|
|
3
4
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
5
|
import { StorageError } from '../storage.error.js';
|
|
@@ -59,6 +60,14 @@ export class StorageFileWorkflow {
|
|
|
59
60
|
signal: AbortSignal.any([boundSignal, restriction.signal].filter((signal) => signal !== undefined)),
|
|
60
61
|
});
|
|
61
62
|
},
|
|
63
|
+
lookup: async (input) => {
|
|
64
|
+
const signal = operation('read', input);
|
|
65
|
+
validateIdentity(input.idempotencyKey);
|
|
66
|
+
return transaction(signal, async (tx) => {
|
|
67
|
+
const draft = await tx.findDraftByKey(input.idempotencyKey);
|
|
68
|
+
return draft === null ? null : summary(draft);
|
|
69
|
+
});
|
|
70
|
+
},
|
|
62
71
|
begin: async (input) => {
|
|
63
72
|
const signal = operation('write', input);
|
|
64
73
|
requireMutation(input.expectedEtag);
|
|
@@ -138,6 +147,61 @@ export class StorageFileWorkflow {
|
|
|
138
147
|
}),
|
|
139
148
|
}));
|
|
140
149
|
},
|
|
150
|
+
stageStream: async (request) => {
|
|
151
|
+
const input = { ...request };
|
|
152
|
+
if (input.sourceDraftId !== undefined)
|
|
153
|
+
operation('read', input);
|
|
154
|
+
const signal = operation('write', input);
|
|
155
|
+
requireMutation(input.expectedEtag);
|
|
156
|
+
validateIdentity(input.idempotencyKey);
|
|
157
|
+
assertWorkspacePath(input.path, limits.maxPathBytes, {
|
|
158
|
+
allowRoot: false,
|
|
159
|
+
});
|
|
160
|
+
if (typeof input.text !== 'boolean' ||
|
|
161
|
+
typeof input.contentIdentity !== 'string' ||
|
|
162
|
+
!input.contentIdentity.length ||
|
|
163
|
+
input.contentIdentity.length > 1024)
|
|
164
|
+
invalid('Invalid streaming draft identity.');
|
|
165
|
+
if (input.expectedEtag !== undefined &&
|
|
166
|
+
(!input.expectedEtag.length || input.expectedEtag.length > 1024))
|
|
167
|
+
invalid('Invalid ETag.');
|
|
168
|
+
return summary(await stageStorageTextDraft({
|
|
169
|
+
scope,
|
|
170
|
+
signal,
|
|
171
|
+
limits,
|
|
172
|
+
content,
|
|
173
|
+
requireMutation,
|
|
174
|
+
transaction: (work) => transaction(signal, work),
|
|
175
|
+
idempotencyKey: input.idempotencyKey,
|
|
176
|
+
fingerprint: digest(new TextEncoder().encode(JSON.stringify([
|
|
177
|
+
'stage-stream',
|
|
178
|
+
input.path,
|
|
179
|
+
input.expectedEtag ?? null,
|
|
180
|
+
input.text,
|
|
181
|
+
input.contentIdentity,
|
|
182
|
+
input.sourceDraftId ?? null,
|
|
183
|
+
input.expectedSize ?? null,
|
|
184
|
+
]))),
|
|
185
|
+
load: async () => {
|
|
186
|
+
const source = input.sourceDraftId === undefined
|
|
187
|
+
? null
|
|
188
|
+
: await transaction(signal, (tx) => requireDraft(tx, input.sourceDraftId));
|
|
189
|
+
if (source !== null &&
|
|
190
|
+
(source.path !== input.path ||
|
|
191
|
+
source.expectedEtag !== (input.expectedEtag ?? null) ||
|
|
192
|
+
source.size !== input.expectedSize ||
|
|
193
|
+
!['open', 'sealed'].includes(source.status)))
|
|
194
|
+
conflict('The source checkpoint changed.');
|
|
195
|
+
return {
|
|
196
|
+
path: input.path,
|
|
197
|
+
expectedEtag: input.expectedEtag ?? null,
|
|
198
|
+
source,
|
|
199
|
+
text: input.text,
|
|
200
|
+
content: input.body(),
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
}));
|
|
204
|
+
},
|
|
141
205
|
reviseText: async (request) => {
|
|
142
206
|
const input = {
|
|
143
207
|
...request,
|
|
@@ -147,10 +211,11 @@ export class StorageFileWorkflow {
|
|
|
147
211
|
const signal = operation('write', input);
|
|
148
212
|
validateIdentity(input.idempotencyKey);
|
|
149
213
|
validateIdentity(input.draftId);
|
|
214
|
+
if (input.requestIdentity !== undefined &&
|
|
215
|
+
input.requestIdentity.length > 4096)
|
|
216
|
+
invalid('Invalid edit request identity.');
|
|
150
217
|
storageInteger(input.expectedSize, 'expectedSize');
|
|
151
|
-
if (input.
|
|
152
|
-
input.changes.length < 1 ||
|
|
153
|
-
input.changes.length > limits.maxEdits)
|
|
218
|
+
if (input.changes.length < 1 || input.changes.length > limits.maxEdits)
|
|
154
219
|
throw new StorageError('Text editing exceeds the configured limits.', { code: 'LIMIT_EXCEEDED' });
|
|
155
220
|
return summary(await stageStorageTextDraft({
|
|
156
221
|
scope,
|
|
@@ -165,6 +230,9 @@ export class StorageFileWorkflow {
|
|
|
165
230
|
input.draftId,
|
|
166
231
|
input.expectedSize,
|
|
167
232
|
input.changes,
|
|
233
|
+
...(input.requestIdentity === undefined
|
|
234
|
+
? []
|
|
235
|
+
: [input.requestIdentity]),
|
|
168
236
|
]))),
|
|
169
237
|
load: async () => {
|
|
170
238
|
const source = await transaction(signal, (tx) => requireDraft(tx, input.draftId));
|
|
@@ -173,16 +241,15 @@ export class StorageFileWorkflow {
|
|
|
173
241
|
!['open', 'sealed'].includes(source.status) ||
|
|
174
242
|
source.size !== input.expectedSize)
|
|
175
243
|
conflict('The source must be an unfinished text draft at the expected size.');
|
|
176
|
-
const bytes = await collectStorageBytes(this.#stream(scope, source, limits, signal), limits.maxTextBytes, signal);
|
|
177
|
-
const original = new TextDecoder('utf-8', {
|
|
178
|
-
fatal: true,
|
|
179
|
-
ignoreBOM: true,
|
|
180
|
-
}).decode(bytes);
|
|
181
244
|
return {
|
|
182
245
|
source,
|
|
183
246
|
path: source.path,
|
|
184
247
|
expectedEtag: source.expectedEtag,
|
|
185
|
-
content:
|
|
248
|
+
content: editStorageTextStream(this.#stream(scope, source, limits, signal), input.changes, {
|
|
249
|
+
maxEditBytes: limits.maxTextBytes,
|
|
250
|
+
maxEdits: limits.maxEdits,
|
|
251
|
+
signal,
|
|
252
|
+
}),
|
|
186
253
|
};
|
|
187
254
|
},
|
|
188
255
|
}));
|
|
@@ -222,6 +289,25 @@ export class StorageFileWorkflow {
|
|
|
222
289
|
: { content: null, offset, nextOffset: null };
|
|
223
290
|
return { ...summary(draft), ...window };
|
|
224
291
|
},
|
|
292
|
+
searchText: async (input) => {
|
|
293
|
+
const signal = operation('read', input);
|
|
294
|
+
const draft = await transaction(signal, (tx) => requireDraft(tx, input.draftId));
|
|
295
|
+
if (!draft.text ||
|
|
296
|
+
draft.status === 'cancelled' ||
|
|
297
|
+
draft.size !== input.expectedSize)
|
|
298
|
+
conflict('The source checkpoint changed.');
|
|
299
|
+
const result = await searchStorageText(async (range) => this.#stream(scope, draft, limits, signal, range.start, range.end + 1), {
|
|
300
|
+
size: draft.size,
|
|
301
|
+
query: input.query,
|
|
302
|
+
offset: input.offset,
|
|
303
|
+
maxScanBytes: 262144,
|
|
304
|
+
maxMatches: 12,
|
|
305
|
+
maxSnippetCharacters: 320,
|
|
306
|
+
maxReadBytes: limits.maxReadBytes,
|
|
307
|
+
signal,
|
|
308
|
+
});
|
|
309
|
+
return { ...result, path: draft.path, etag: draft.id };
|
|
310
|
+
},
|
|
225
311
|
readText: async (request) => {
|
|
226
312
|
const input = { ...request };
|
|
227
313
|
const signal = operation('read', input);
|