@effect-kit/storage 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/LICENSE +204 -0
- package/README.md +369 -2
- package/dist/_virtual/_rolldown/runtime.js +17 -0
- package/dist/azure/account-admin.d.ts +116 -0
- package/dist/azure/account-admin.js +90 -0
- package/dist/azure/account-admin.js.map +1 -0
- package/dist/azure/admin.d.ts +68 -0
- package/dist/azure/admin.js +85 -0
- package/dist/azure/admin.js.map +1 -0
- package/dist/azure/archive.d.ts +95 -0
- package/dist/azure/archive.js +52 -0
- package/dist/azure/archive.js.map +1 -0
- package/dist/azure/events.d.ts +40 -0
- package/dist/azure/events.js +62 -0
- package/dist/azure/events.js.map +1 -0
- package/dist/azure/governance.d.ts +139 -0
- package/dist/azure/governance.js +59 -0
- package/dist/azure/governance.js.map +1 -0
- package/dist/azure/identity.d.ts +4 -0
- package/dist/azure/identity.js +8 -0
- package/dist/azure/identity.js.map +1 -0
- package/dist/azure/lifecycle.d.ts +21 -0
- package/dist/azure/lifecycle.js +193 -0
- package/dist/azure/lifecycle.js.map +1 -0
- package/dist/azure/signing.d.ts +17 -0
- package/dist/azure/signing.js +71 -0
- package/dist/azure/signing.js.map +1 -0
- package/dist/azure/uploads.d.ts +11 -0
- package/dist/azure/uploads.js +83 -0
- package/dist/azure/uploads.js.map +1 -0
- package/dist/azure.d.ts +427 -0
- package/dist/azure.js +77 -0
- package/dist/azure.js.map +1 -0
- package/dist/b2/admin.d.ts +149 -0
- package/dist/b2/admin.js +157 -0
- package/dist/b2/admin.js.map +1 -0
- package/dist/b2.d.ts +15 -0
- package/dist/b2.js +15 -0
- package/dist/b2.js.map +1 -0
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +11 -0
- package/dist/browser.js.map +1 -0
- package/dist/bun.d.ts +14 -0
- package/dist/bun.js +17 -0
- package/dist/bun.js.map +1 -0
- package/dist/cache.d.ts +18 -0
- package/dist/cache.js +116 -0
- package/dist/cache.js.map +1 -0
- package/dist/client/atoms/controller.d.ts +10 -0
- package/dist/client/atoms/controller.js +267 -0
- package/dist/client/atoms/controller.js.map +1 -0
- package/dist/client/atoms/state.d.ts +17 -0
- package/dist/client/atoms/state.js +11 -0
- package/dist/client/atoms/state.js.map +1 -0
- package/dist/client/atoms.d.ts +59 -0
- package/dist/client/atoms.js +39 -0
- package/dist/client/atoms.js.map +1 -0
- package/dist/client/fingerprint.js +28 -0
- package/dist/client/fingerprint.js.map +1 -0
- package/dist/client/store.d.ts +31 -0
- package/dist/client/store.js +56 -0
- package/dist/client/store.js.map +1 -0
- package/dist/client/transport.d.ts +11 -0
- package/dist/client/transport.js +78 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/client.d.ts +259 -0
- package/dist/client.js +350 -0
- package/dist/client.js.map +1 -0
- package/dist/composition/layer.js +22 -0
- package/dist/composition/layer.js.map +1 -0
- package/dist/composition/representation/staging.js +46 -0
- package/dist/composition/representation/staging.js.map +1 -0
- package/dist/composition/representation/storage.js +188 -0
- package/dist/composition/representation/storage.js.map +1 -0
- package/dist/composition.d.ts +20 -0
- package/dist/composition.js +124 -0
- package/dist/composition.js.map +1 -0
- package/dist/compression.d.ts +16 -0
- package/dist/compression.js +38 -0
- package/dist/compression.js.map +1 -0
- package/dist/content.d.ts +590 -0
- package/dist/content.js +168 -0
- package/dist/content.js.map +1 -0
- package/dist/core/capabilities.d.ts +53 -0
- package/dist/core/capabilities.js +9 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/contracts/multipart.d.ts +56 -0
- package/dist/core/contracts/resumable.d.ts +70 -0
- package/dist/core/errors.d.ts +55 -0
- package/dist/core/errors.js +55 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/object.d.ts +97 -0
- package/dist/core/object.js +55 -0
- package/dist/core/object.js.map +1 -0
- package/dist/core/ranges.d.ts +17 -0
- package/dist/core/ranges.js +27 -0
- package/dist/core/ranges.js.map +1 -0
- package/dist/core/requests.d.ts +185 -0
- package/dist/core/requests.js +42 -0
- package/dist/core/requests.js.map +1 -0
- package/dist/core/storage.d.ts +249 -0
- package/dist/core/storage.js +173 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/deno.d.ts +14 -0
- package/dist/deno.js +17 -0
- package/dist/deno.js.map +1 -0
- package/dist/encryption/age.d.ts +14 -0
- package/dist/encryption/age.js +46 -0
- package/dist/encryption/age.js.map +1 -0
- package/dist/encryption.d.ts +16 -0
- package/dist/encryption.js +16 -0
- package/dist/encryption.js.map +1 -0
- package/dist/events.d.ts +57 -0
- package/dist/events.js +106 -0
- package/dist/events.js.map +1 -0
- package/dist/filesystem.d.ts +23 -0
- package/dist/filesystem.js +75 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/gcs/admin.d.ts +470 -0
- package/dist/gcs/admin.js +206 -0
- package/dist/gcs/admin.js.map +1 -0
- package/dist/gcs/events.d.ts +41 -0
- package/dist/gcs/events.js +45 -0
- package/dist/gcs/events.js.map +1 -0
- package/dist/gcs/governance.d.ts +158 -0
- package/dist/gcs/governance.js +100 -0
- package/dist/gcs/governance.js.map +1 -0
- package/dist/gcs/lifecycle.d.ts +161 -0
- package/dist/gcs/lifecycle.js +174 -0
- package/dist/gcs/lifecycle.js.map +1 -0
- package/dist/gcs/post.d.ts +31 -0
- package/dist/gcs/post.js +70 -0
- package/dist/gcs/post.js.map +1 -0
- package/dist/gcs/signing.d.ts +10 -0
- package/dist/gcs/signing.js +61 -0
- package/dist/gcs/signing.js.map +1 -0
- package/dist/gcs/uploads.d.ts +10 -0
- package/dist/gcs/uploads.js +76 -0
- package/dist/gcs/uploads.js.map +1 -0
- package/dist/gcs.d.ts +888 -0
- package/dist/gcs.js +91 -0
- package/dist/gcs.js.map +1 -0
- package/dist/hetzner/admin.d.ts +112 -0
- package/dist/hetzner/admin.js +19 -0
- package/dist/hetzner/admin.js.map +1 -0
- package/dist/hetzner.d.ts +15 -0
- package/dist/hetzner.js +15 -0
- package/dist/hetzner.js.map +1 -0
- package/dist/http/api.d.ts +236 -0
- package/dist/http/api.js +54 -0
- package/dist/http/api.js.map +1 -0
- package/dist/http/download.js +99 -0
- package/dist/http/download.js.map +1 -0
- package/dist/http/schema.d.ts +3 -0
- package/dist/http/schema.js +4 -0
- package/dist/http.d.ts +35 -0
- package/dist/http.js +178 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/internal/http/control-plane.js +71 -0
- package/dist/internal/http/control-plane.js.map +1 -0
- package/dist/internal/listing-cursor.js +44 -0
- package/dist/internal/listing-cursor.js.map +1 -0
- package/dist/internal/node/provider-errors.js +16 -0
- package/dist/internal/node/provider-errors.js.map +1 -0
- package/dist/internal/node/upload-body.js +111 -0
- package/dist/internal/node/upload-body.js.map +1 -0
- package/dist/internal/provider-response.js +14 -0
- package/dist/internal/provider-response.js.map +1 -0
- package/dist/internal/public-urls.js +30 -0
- package/dist/internal/public-urls.js.map +1 -0
- package/dist/internal/read-condition.js +11 -0
- package/dist/internal/read-condition.js.map +1 -0
- package/dist/internal/request-validation.js +24 -0
- package/dist/internal/request-validation.js.map +1 -0
- package/dist/internal/signing-request.js +22 -0
- package/dist/internal/signing-request.js.map +1 -0
- package/dist/internal/web-upload-body.js +71 -0
- package/dist/internal/web-upload-body.js.map +1 -0
- package/dist/lifecycle/configuration-state.js +26 -0
- package/dist/lifecycle/configuration-state.js.map +1 -0
- package/dist/lifecycle/metadata.js +28 -0
- package/dist/lifecycle/metadata.js.map +1 -0
- package/dist/lifecycle.d.ts +269 -0
- package/dist/lifecycle.js +72 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/migrations.d.ts +537 -0
- package/dist/migrations.js +296 -0
- package/dist/migrations.js.map +1 -0
- package/dist/minio/admin.d.ts +112 -0
- package/dist/minio/admin.js +19 -0
- package/dist/minio/admin.js.map +1 -0
- package/dist/minio.d.ts +15 -0
- package/dist/minio.js +15 -0
- package/dist/minio.js.map +1 -0
- package/dist/mirror.d.ts +830 -0
- package/dist/mirror.js +290 -0
- package/dist/mirror.js.map +1 -0
- package/dist/node.d.ts +14 -0
- package/dist/node.js +17 -0
- package/dist/node.js.map +1 -0
- package/dist/providers/azure/blocks.js +94 -0
- package/dist/providers/azure/blocks.js.map +1 -0
- package/dist/providers/azure/config.d.ts +41 -0
- package/dist/providers/azure/config.js +62 -0
- package/dist/providers/azure/config.js.map +1 -0
- package/dist/providers/azure/mapping.js +83 -0
- package/dist/providers/azure/mapping.js.map +1 -0
- package/dist/providers/azure/native.js +88 -0
- package/dist/providers/azure/native.js.map +1 -0
- package/dist/providers/azure/primitives.js +203 -0
- package/dist/providers/azure/primitives.js.map +1 -0
- package/dist/providers/azure/properties.d.ts +180 -0
- package/dist/providers/azure/properties.js +55 -0
- package/dist/providers/azure/properties.js.map +1 -0
- package/dist/providers/azure/transport.js +14 -0
- package/dist/providers/azure/transport.js.map +1 -0
- package/dist/providers/azure/validation.js +11 -0
- package/dist/providers/azure/validation.js.map +1 -0
- package/dist/providers/filesystem/envelope.js +56 -0
- package/dist/providers/filesystem/envelope.js.map +1 -0
- package/dist/providers/filesystem/identity.js +68 -0
- package/dist/providers/filesystem/identity.js.map +1 -0
- package/dist/providers/filesystem/layout.d.ts +15 -0
- package/dist/providers/filesystem/layout.js +112 -0
- package/dist/providers/filesystem/layout.js.map +1 -0
- package/dist/providers/filesystem/list.js +82 -0
- package/dist/providers/filesystem/list.js.map +1 -0
- package/dist/providers/filesystem/operations.js +134 -0
- package/dist/providers/filesystem/operations.js.map +1 -0
- package/dist/providers/gcs/config.d.ts +34 -0
- package/dist/providers/gcs/config.js +60 -0
- package/dist/providers/gcs/config.js.map +1 -0
- package/dist/providers/gcs/iam.js +45 -0
- package/dist/providers/gcs/iam.js.map +1 -0
- package/dist/providers/gcs/mapping.js +118 -0
- package/dist/providers/gcs/mapping.js.map +1 -0
- package/dist/providers/gcs/native.d.ts +11 -0
- package/dist/providers/gcs/native.js +122 -0
- package/dist/providers/gcs/native.js.map +1 -0
- package/dist/providers/gcs/primitives.js +194 -0
- package/dist/providers/gcs/primitives.js.map +1 -0
- package/dist/providers/gcs/resumable.js +145 -0
- package/dist/providers/gcs/resumable.js.map +1 -0
- package/dist/providers/gcs/tier.d.ts +176 -0
- package/dist/providers/gcs/tier.js +34 -0
- package/dist/providers/gcs/tier.js.map +1 -0
- package/dist/providers/gcs/transport.js +123 -0
- package/dist/providers/gcs/transport.js.map +1 -0
- package/dist/providers/gcs/upload.js +28 -0
- package/dist/providers/gcs/upload.js.map +1 -0
- package/dist/providers/gcs/validation.js +10 -0
- package/dist/providers/gcs/validation.js.map +1 -0
- package/dist/providers/r2-workers/binding.d.ts +102 -0
- package/dist/providers/r2-workers/body.js +82 -0
- package/dist/providers/r2-workers/body.js.map +1 -0
- package/dist/providers/r2-workers/list.js +62 -0
- package/dist/providers/r2-workers/list.js.map +1 -0
- package/dist/providers/r2-workers/mapping.js +140 -0
- package/dist/providers/r2-workers/mapping.js.map +1 -0
- package/dist/providers/r2-workers/multipart.js +121 -0
- package/dist/providers/r2-workers/multipart.js.map +1 -0
- package/dist/providers/r2-workers/primitives.js +80 -0
- package/dist/providers/r2-workers/primitives.js.map +1 -0
- package/dist/providers/s3/admin-configuration.d.ts +19 -0
- package/dist/providers/s3/admin-configuration.js +171 -0
- package/dist/providers/s3/admin-configuration.js.map +1 -0
- package/dist/providers/s3/bulk-delete.d.ts +43 -0
- package/dist/providers/s3/bulk-delete.js +58 -0
- package/dist/providers/s3/bulk-delete.js.map +1 -0
- package/dist/providers/s3/config.d.ts +43 -0
- package/dist/providers/s3/config.js +89 -0
- package/dist/providers/s3/config.js.map +1 -0
- package/dist/providers/s3/copy.d.ts +115 -0
- package/dist/providers/s3/copy.js +122 -0
- package/dist/providers/s3/copy.js.map +1 -0
- package/dist/providers/s3/lifecycle-validation.js +33 -0
- package/dist/providers/s3/lifecycle-validation.js.map +1 -0
- package/dist/providers/s3/listing.js +56 -0
- package/dist/providers/s3/listing.js.map +1 -0
- package/dist/providers/s3/metadata.d.ts +10 -0
- package/dist/providers/s3/metadata.js +90 -0
- package/dist/providers/s3/metadata.js.map +1 -0
- package/dist/providers/s3/multipart.d.ts +41 -0
- package/dist/providers/s3/multipart.js +299 -0
- package/dist/providers/s3/multipart.js.map +1 -0
- package/dist/providers/s3/native-models.d.ts +82 -0
- package/dist/providers/s3/native-models.js +91 -0
- package/dist/providers/s3/native-models.js.map +1 -0
- package/dist/providers/s3/object-mapping.js +114 -0
- package/dist/providers/s3/object-mapping.js.map +1 -0
- package/dist/providers/s3/primitives.d.ts +8 -0
- package/dist/providers/s3/primitives.js +235 -0
- package/dist/providers/s3/primitives.js.map +1 -0
- package/dist/providers/s3/profile.d.ts +25 -0
- package/dist/providers/s3/profile.js +46 -0
- package/dist/providers/s3/profile.js.map +1 -0
- package/dist/providers/s3/request-extension.js +29 -0
- package/dist/providers/s3/request-extension.js.map +1 -0
- package/dist/providers/s3/service.js +55 -0
- package/dist/providers/s3/service.js.map +1 -0
- package/dist/providers/s3/signing-credentials.js +32 -0
- package/dist/providers/s3/signing-credentials.js.map +1 -0
- package/dist/providers/s3/tags.d.ts +10 -0
- package/dist/providers/s3/tags.js +65 -0
- package/dist/providers/s3/tags.js.map +1 -0
- package/dist/providers/s3/tier.d.ts +171 -0
- package/dist/providers/s3/tier.js +100 -0
- package/dist/providers/s3/tier.js.map +1 -0
- package/dist/providers/s3/transfer-driver.js +72 -0
- package/dist/providers/s3/transfer-driver.js.map +1 -0
- package/dist/providers/s3/transport.js +94 -0
- package/dist/providers/s3/transport.js.map +1 -0
- package/dist/providers/s3/upload-body.js +10 -0
- package/dist/providers/s3/upload-body.js.map +1 -0
- package/dist/providers/s3/validation.js +31 -0
- package/dist/providers/s3/validation.js.map +1 -0
- package/dist/providers/s3/versions.d.ts +10 -0
- package/dist/providers/s3/versions.js +143 -0
- package/dist/providers/s3/versions.js.map +1 -0
- package/dist/providers/s3-compatible/config.d.ts +36 -0
- package/dist/providers/s3-compatible/config.js +174 -0
- package/dist/providers/s3-compatible/config.js.map +1 -0
- package/dist/providers/s3-compatible/service.js +48 -0
- package/dist/providers/s3-compatible/service.js.map +1 -0
- package/dist/providers/supabase/config.d.ts +20 -0
- package/dist/providers/supabase/config.js +41 -0
- package/dist/providers/supabase/config.js.map +1 -0
- package/dist/providers/supabase/mapping.js +60 -0
- package/dist/providers/supabase/mapping.js.map +1 -0
- package/dist/providers/supabase/primitives.js +205 -0
- package/dist/providers/supabase/primitives.js.map +1 -0
- package/dist/providers/supabase/transport.js +64 -0
- package/dist/providers/supabase/transport.js.map +1 -0
- package/dist/providers/supabase/tus.js +163 -0
- package/dist/providers/supabase/tus.js.map +1 -0
- package/dist/providers/tigris/configuration.js +118 -0
- package/dist/providers/tigris/configuration.js.map +1 -0
- package/dist/providers/tigris/snapshots.js +87 -0
- package/dist/providers/tigris/snapshots.js.map +1 -0
- package/dist/providers/tigris/transport.js +18 -0
- package/dist/providers/tigris/transport.js.map +1 -0
- package/dist/providers/vercel/config.d.ts +16 -0
- package/dist/providers/vercel/config.js +48 -0
- package/dist/providers/vercel/config.js.map +1 -0
- package/dist/providers/vercel/mapping.js +79 -0
- package/dist/providers/vercel/mapping.js.map +1 -0
- package/dist/providers/vercel/multipart.js +113 -0
- package/dist/providers/vercel/multipart.js.map +1 -0
- package/dist/providers/vercel/primitives.js +168 -0
- package/dist/providers/vercel/primitives.js.map +1 -0
- package/dist/providers/vercel/transport.js +32 -0
- package/dist/providers/vercel/transport.js.map +1 -0
- package/dist/providers/wasabi/compliance.d.ts +52 -0
- package/dist/providers/wasabi/compliance.js +89 -0
- package/dist/providers/wasabi/compliance.js.map +1 -0
- package/dist/providers/wasabi/xml.js +55 -0
- package/dist/providers/wasabi/xml.js.map +1 -0
- package/dist/r2/admin.d.ts +126 -0
- package/dist/r2/admin.js +138 -0
- package/dist/r2/admin.js.map +1 -0
- package/dist/r2/events.d.ts +41 -0
- package/dist/r2/events.js +37 -0
- package/dist/r2/events.js.map +1 -0
- package/dist/r2-workers.d.ts +24 -0
- package/dist/r2-workers.js +115 -0
- package/dist/r2-workers.js.map +1 -0
- package/dist/r2.d.ts +15 -0
- package/dist/r2.js +15 -0
- package/dist/r2.js.map +1 -0
- package/dist/react.d.ts +73 -0
- package/dist/react.js +49 -0
- package/dist/react.js.map +1 -0
- package/dist/representation.d.ts +24 -0
- package/dist/representation.js +7 -0
- package/dist/representation.js.map +1 -0
- package/dist/runtime/bun-filesystem.js +136 -0
- package/dist/runtime/bun-filesystem.js.map +1 -0
- package/dist/runtime/file-target.d.ts +10 -0
- package/dist/runtime/file-target.js +66 -0
- package/dist/runtime/file-target.js.map +1 -0
- package/dist/runtime/filesystem.d.ts +6 -0
- package/dist/runtime/filesystem.js +68 -0
- package/dist/runtime/filesystem.js.map +1 -0
- package/dist/runtime/node-hash.d.ts +4 -0
- package/dist/runtime/node-hash.js +31 -0
- package/dist/runtime/node-hash.js.map +1 -0
- package/dist/runtime/node-protection.d.ts +4 -0
- package/dist/runtime/node-protection.js +46 -0
- package/dist/runtime/node-protection.js.map +1 -0
- package/dist/runtime/portable-hash.d.ts +3 -0
- package/dist/runtime/portable-hash.js +31 -0
- package/dist/runtime/portable-hash.js.map +1 -0
- package/dist/runtime/session-store.d.ts +12 -0
- package/dist/runtime/session-store.js +19 -0
- package/dist/runtime/session-store.js.map +1 -0
- package/dist/runtime/web-protection.d.ts +7 -0
- package/dist/runtime/web-protection.js +54 -0
- package/dist/runtime/web-protection.js.map +1 -0
- package/dist/s3/admin.d.ts +183 -0
- package/dist/s3/admin.js +197 -0
- package/dist/s3/admin.js.map +1 -0
- package/dist/s3/archive.d.ts +25 -0
- package/dist/s3/archive.js +113 -0
- package/dist/s3/archive.js.map +1 -0
- package/dist/s3/events.d.ts +42 -0
- package/dist/s3/events.js +69 -0
- package/dist/s3/events.js.map +1 -0
- package/dist/s3/governance.d.ts +319 -0
- package/dist/s3/governance.js +108 -0
- package/dist/s3/governance.js.map +1 -0
- package/dist/s3/lifecycle.d.ts +4 -0
- package/dist/s3/lifecycle.js +5 -0
- package/dist/s3/post.d.ts +31 -0
- package/dist/s3/post.js +93 -0
- package/dist/s3/post.js.map +1 -0
- package/dist/s3/signing.d.ts +105 -0
- package/dist/s3/signing.js +198 -0
- package/dist/s3/signing.js.map +1 -0
- package/dist/s3/uploads.d.ts +11 -0
- package/dist/s3/uploads.js +173 -0
- package/dist/s3/uploads.js.map +1 -0
- package/dist/s3.d.ts +37 -0
- package/dist/s3.js +114 -0
- package/dist/s3.js.map +1 -0
- package/dist/scaleway/admin.d.ts +112 -0
- package/dist/scaleway/admin.js +19 -0
- package/dist/scaleway/admin.js.map +1 -0
- package/dist/scaleway.d.ts +15 -0
- package/dist/scaleway.js +15 -0
- package/dist/scaleway.js.map +1 -0
- package/dist/session-events.d.ts +22 -0
- package/dist/session-events.js +22 -0
- package/dist/session-events.js.map +1 -0
- package/dist/sessions/checkpoint.d.ts +423 -0
- package/dist/sessions/checkpoint.js +102 -0
- package/dist/sessions/checkpoint.js.map +1 -0
- package/dist/sessions/download.d.ts +17 -0
- package/dist/sessions/download.js +111 -0
- package/dist/sessions/download.js.map +1 -0
- package/dist/sessions/native-upload.js +168 -0
- package/dist/sessions/native-upload.js.map +1 -0
- package/dist/sessions/store.d.ts +40 -0
- package/dist/sessions/store.js +77 -0
- package/dist/sessions/store.js.map +1 -0
- package/dist/sessions/upload.d.ts +10 -0
- package/dist/sessions/upload.js +329 -0
- package/dist/sessions/upload.js.map +1 -0
- package/dist/sessions.d.ts +98 -0
- package/dist/sessions.js +268 -0
- package/dist/sessions.js.map +1 -0
- package/dist/spaces/admin.d.ts +112 -0
- package/dist/spaces/admin.js +19 -0
- package/dist/spaces/admin.js.map +1 -0
- package/dist/spaces.d.ts +15 -0
- package/dist/spaces.js +15 -0
- package/dist/spaces.js.map +1 -0
- package/dist/supabase/admin.d.ts +77 -0
- package/dist/supabase/admin.js +74 -0
- package/dist/supabase/admin.js.map +1 -0
- package/dist/supabase/s3.d.ts +311 -0
- package/dist/supabase/s3.js +153 -0
- package/dist/supabase/s3.js.map +1 -0
- package/dist/supabase/signing.d.ts +23 -0
- package/dist/supabase/signing.js +93 -0
- package/dist/supabase/signing.js.map +1 -0
- package/dist/supabase/tus-uploads.d.ts +13 -0
- package/dist/supabase/tus-uploads.js +109 -0
- package/dist/supabase/tus-uploads.js.map +1 -0
- package/dist/supabase/uploads.d.ts +5 -0
- package/dist/supabase/uploads.js +32 -0
- package/dist/supabase/uploads.js.map +1 -0
- package/dist/supabase.d.ts +100 -0
- package/dist/supabase.js +50 -0
- package/dist/supabase.js.map +1 -0
- package/dist/testing/body-failure.js +18 -0
- package/dist/testing/body-failure.js.map +1 -0
- package/dist/testing/conformance/assertions.d.ts +10 -0
- package/dist/testing/conformance/assertions.js +21 -0
- package/dist/testing/conformance/assertions.js.map +1 -0
- package/dist/testing/conformance/core-cases.js +107 -0
- package/dist/testing/conformance/core-cases.js.map +1 -0
- package/dist/testing/conformance/list-cases.js +72 -0
- package/dist/testing/conformance/list-cases.js.map +1 -0
- package/dist/testing/conformance/read-cases.js +105 -0
- package/dist/testing/conformance/read-cases.js.map +1 -0
- package/dist/testing/conformance.d.ts +23 -0
- package/dist/testing/conformance.js +37 -0
- package/dist/testing/conformance.js.map +1 -0
- package/dist/testing/faults.d.ts +258 -0
- package/dist/testing/faults.js +111 -0
- package/dist/testing/faults.js.map +1 -0
- package/dist/testing/memory-list.js +79 -0
- package/dist/testing/memory-list.js.map +1 -0
- package/dist/testing/memory-state.d.ts +18 -0
- package/dist/testing/memory-state.js +57 -0
- package/dist/testing/memory-state.js.map +1 -0
- package/dist/testing/memory-upload.js +123 -0
- package/dist/testing/memory-upload.js.map +1 -0
- package/dist/testing/memory.d.ts +23 -0
- package/dist/testing/memory.js +121 -0
- package/dist/testing/memory.js.map +1 -0
- package/dist/testing.d.ts +6 -0
- package/dist/testing.js +6 -0
- package/dist/tigris/events.d.ts +42 -0
- package/dist/tigris/events.js +42 -0
- package/dist/tigris/events.js.map +1 -0
- package/dist/tigris/native.d.ts +438 -0
- package/dist/tigris/native.js +166 -0
- package/dist/tigris/native.js.map +1 -0
- package/dist/tigris.d.ts +15 -0
- package/dist/tigris.js +15 -0
- package/dist/tigris.js.map +1 -0
- package/dist/transfers/budget.js +50 -0
- package/dist/transfers/budget.js.map +1 -0
- package/dist/transfers/copy.js +250 -0
- package/dist/transfers/copy.js.map +1 -0
- package/dist/transfers/dependencies.d.ts +10 -0
- package/dist/transfers/dependencies.js +11 -0
- package/dist/transfers/dependencies.js.map +1 -0
- package/dist/transfers/download.js +132 -0
- package/dist/transfers/download.js.map +1 -0
- package/dist/transfers/managed-runtime.d.ts +34 -0
- package/dist/transfers/managed-runtime.js +30 -0
- package/dist/transfers/managed-runtime.js.map +1 -0
- package/dist/transfers/models.d.ts +160 -0
- package/dist/transfers/native-upload.js +195 -0
- package/dist/transfers/native-upload.js.map +1 -0
- package/dist/transfers/part-receipts.js +32 -0
- package/dist/transfers/part-receipts.js.map +1 -0
- package/dist/transfers/planner.d.ts +19 -0
- package/dist/transfers/planner.js +153 -0
- package/dist/transfers/planner.js.map +1 -0
- package/dist/transfers/reader.js +81 -0
- package/dist/transfers/reader.js.map +1 -0
- package/dist/transfers/runtime.d.ts +19 -0
- package/dist/transfers/runtime.js +132 -0
- package/dist/transfers/runtime.js.map +1 -0
- package/dist/transfers/sources.d.ts +22 -0
- package/dist/transfers/sources.js +83 -0
- package/dist/transfers/sources.js.map +1 -0
- package/dist/transfers/upload.js +235 -0
- package/dist/transfers/upload.js.map +1 -0
- package/dist/transfers.d.ts +31 -0
- package/dist/transfers.js +82 -0
- package/dist/transfers.js.map +1 -0
- package/dist/uploads/driver.d.ts +22 -0
- package/dist/uploads/driver.js +18 -0
- package/dist/uploads/driver.js.map +1 -0
- package/dist/uploads/policy.d.ts +39 -0
- package/dist/uploads/schema.d.ts +278 -0
- package/dist/uploads/schema.js +167 -0
- package/dist/uploads/schema.js.map +1 -0
- package/dist/uploads/signed-driver.d.ts +8 -0
- package/dist/uploads/signed-driver.js +36 -0
- package/dist/uploads/signed-driver.js.map +1 -0
- package/dist/uploads/store.d.ts +26 -0
- package/dist/uploads/store.js +51 -0
- package/dist/uploads/store.js.map +1 -0
- package/dist/uploads/verification.js +86 -0
- package/dist/uploads/verification.js.map +1 -0
- package/dist/uploads.d.ts +518 -0
- package/dist/uploads.js +330 -0
- package/dist/uploads.js.map +1 -0
- package/dist/vercel/authorized-uploads.d.ts +7 -0
- package/dist/vercel/authorized-uploads.js +15 -0
- package/dist/vercel/authorized-uploads.js.map +1 -0
- package/dist/vercel/client.d.ts +16 -0
- package/dist/vercel/client.js +28 -0
- package/dist/vercel/client.js.map +1 -0
- package/dist/vercel/signing.d.ts +19 -0
- package/dist/vercel/signing.js +120 -0
- package/dist/vercel/signing.js.map +1 -0
- package/dist/vercel/uploads.d.ts +36 -0
- package/dist/vercel/uploads.js +161 -0
- package/dist/vercel/uploads.js.map +1 -0
- package/dist/vercel.d.ts +86 -0
- package/dist/vercel.js +46 -0
- package/dist/vercel.js.map +1 -0
- package/dist/wasabi/admin.d.ts +112 -0
- package/dist/wasabi/admin.js +19 -0
- package/dist/wasabi/admin.js.map +1 -0
- package/dist/wasabi/native.d.ts +200 -0
- package/dist/wasabi/native.js +132 -0
- package/dist/wasabi/native.js.map +1 -0
- package/dist/wasabi.d.ts +15 -0
- package/dist/wasabi.js +15 -0
- package/dist/wasabi.js.map +1 -0
- package/dist/workflows/content/collection.js +122 -0
- package/dist/workflows/content/collection.js.map +1 -0
- package/dist/workflows/content/references.js +113 -0
- package/dist/workflows/content/references.js.map +1 -0
- package/dist/workflows/content/schema.d.ts +58 -0
- package/dist/workflows/content/schema.js +64 -0
- package/dist/workflows/content/schema.js.map +1 -0
- package/dist/workflows/endpoint.js +16 -0
- package/dist/workflows/endpoint.js.map +1 -0
- package/dist/workflows/migrations/schema.d.ts +149 -0
- package/dist/workflows/migrations/schema.js +58 -0
- package/dist/workflows/migrations/schema.js.map +1 -0
- package/dist/workflows/mirror/operations.js +175 -0
- package/dist/workflows/mirror/operations.js.map +1 -0
- package/dist/workflows/mirror/schema.d.ts +68 -0
- package/dist/workflows/mirror/schema.js +57 -0
- package/dist/workflows/mirror/schema.js.map +1 -0
- package/dist/workflows/mirror/view.js +103 -0
- package/dist/workflows/mirror/view.js.map +1 -0
- package/dist/workflows/objects.js +54 -0
- package/dist/workflows/objects.js.map +1 -0
- package/dist/workflows/store.d.ts +13 -0
- package/dist/workflows/store.js +58 -0
- package/dist/workflows/store.js.map +1 -0
- package/package.json +513 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { storageError } from "../../core/errors.js";
|
|
2
|
+
import { decodeRequest } from "../../internal/request-validation.js";
|
|
3
|
+
import { encryption, lease } from "./config.js";
|
|
4
|
+
import { metadata, nativeHeaders, target } from "./mapping.js";
|
|
5
|
+
import { request } from "./transport.js";
|
|
6
|
+
import { AzureStorage } from "../../azure.js";
|
|
7
|
+
import { MetadataReplace } from "../../lifecycle.js";
|
|
8
|
+
import { replaceHeaders } from "../../lifecycle/metadata.js";
|
|
9
|
+
import { Context, Effect, Layer } from "effect";
|
|
10
|
+
|
|
11
|
+
// src/providers/azure/properties.ts
|
|
12
|
+
const make = (storage) => ({
|
|
13
|
+
/** Azure writes system headers separately from custom metadata. Each operation has its own CAS. */
|
|
14
|
+
setHeaders: Effect.fnUntraced(function* (input) {
|
|
15
|
+
const value = yield* decodeRequest(MetadataReplace, input, "setHeaders", "azure", true);
|
|
16
|
+
if (value.ref.version || value.condition?._tag !== "IfMatch" || value.headers.customMetadata) return yield* storageError("setHeaders", "azure", {
|
|
17
|
+
_tag: "InvalidInput",
|
|
18
|
+
field: "current-if-match-system-headers"
|
|
19
|
+
}, "not-started");
|
|
20
|
+
const address = yield* target(storage, { ref: value.ref }, "setHeaders");
|
|
21
|
+
const conditions = {
|
|
22
|
+
ifMatch: value.condition.etag,
|
|
23
|
+
...lease(storage.config)
|
|
24
|
+
};
|
|
25
|
+
const before = yield* request(storage, "setHeaders.head", false, (signal) => address.client.getProperties({
|
|
26
|
+
abortSignal: signal,
|
|
27
|
+
conditions,
|
|
28
|
+
...encryption(storage.config)
|
|
29
|
+
}));
|
|
30
|
+
const previous = metadata(storage, value.ref.key, before);
|
|
31
|
+
const headers = replaceHeaders(previous, value.headers);
|
|
32
|
+
const output = yield* request(storage, "setHeaders", true, (signal) => address.client.setHTTPHeaders(nativeHeaders(headers), {
|
|
33
|
+
abortSignal: signal,
|
|
34
|
+
conditions
|
|
35
|
+
}));
|
|
36
|
+
if (!output.etag) return yield* storageError("setHeaders", "azure", {
|
|
37
|
+
_tag: "ProviderFailure",
|
|
38
|
+
code: "MissingHeadersReceipt"
|
|
39
|
+
}, "unknown");
|
|
40
|
+
return {
|
|
41
|
+
...metadata(storage, value.ref.key, {
|
|
42
|
+
...before,
|
|
43
|
+
versionId: void 0,
|
|
44
|
+
...output
|
|
45
|
+
}),
|
|
46
|
+
...value.headers
|
|
47
|
+
};
|
|
48
|
+
}) });
|
|
49
|
+
var AzureProperties = class AzureProperties extends Context.Service()("@effect-kit/storage/azure/AzureProperties") {
|
|
50
|
+
static make = make;
|
|
51
|
+
static layer = Layer.effect(AzureProperties, Effect.map(AzureStorage, make));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export { AzureProperties };
|
|
55
|
+
//# sourceMappingURL=properties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"properties.js","names":[],"sources":["../../../src/providers/azure/properties.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nimport { storageError } from \"../../core/errors.js\";\nimport { decodeRequest } from \"../../internal/request-validation.js\";\nimport { MetadataReplace } from \"../../lifecycle/index.js\";\nimport { replaceHeaders } from \"../../lifecycle/metadata.js\";\nimport { encryption, lease } from \"./config.js\";\nimport { AzureStorage } from \"./index.js\";\nimport type { AzureStorageService } from \"./index.js\";\nimport { metadata, nativeHeaders, target } from \"./mapping.js\";\nimport { request } from \"./transport.js\";\n\nconst make = (storage: AzureStorageService) => ({\n /** Azure writes system headers separately from custom metadata. Each operation has its own CAS. */\n setHeaders: Effect.fnUntraced(function* (input: typeof MetadataReplace.Type) {\n const value = yield* decodeRequest(MetadataReplace, input, \"setHeaders\", \"azure\", true);\n if (value.ref.version || value.condition?._tag !== \"IfMatch\" || value.headers.customMetadata)\n return yield* storageError(\n \"setHeaders\",\n \"azure\",\n { _tag: \"InvalidInput\", field: \"current-if-match-system-headers\" },\n \"not-started\",\n );\n const address = yield* target(storage, { ref: value.ref }, \"setHeaders\");\n const conditions = { ifMatch: value.condition.etag, ...lease(storage.config) };\n const before = yield* request(storage, \"setHeaders.head\", false, (signal) =>\n address.client.getProperties({\n abortSignal: signal,\n conditions,\n ...encryption(storage.config),\n }),\n );\n const previous = metadata(storage, value.ref.key, before);\n const headers = replaceHeaders(previous, value.headers);\n const output = yield* request(storage, \"setHeaders\", true, (signal) =>\n address.client.setHTTPHeaders(nativeHeaders(headers), { abortSignal: signal, conditions }),\n );\n if (!output.etag)\n return yield* storageError(\n \"setHeaders\",\n \"azure\",\n { _tag: \"ProviderFailure\", code: \"MissingHeadersReceipt\" },\n \"unknown\",\n );\n return {\n ...metadata(storage, value.ref.key, { ...before, versionId: undefined, ...output }),\n ...value.headers,\n };\n }),\n});\nexport class AzureProperties extends Context.Service<AzureProperties, ReturnType<typeof make>>()(\n \"@effect-kit/storage/azure/AzureProperties\",\n) {\n static readonly make = make;\n static readonly layer = Layer.effect(AzureProperties, Effect.map(AzureStorage, make));\n}\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,QAAQ,aAAkC;;AAE9C,YAAY,OAAO,WAAW,WAAW,OAAoC;CAC3E,MAAM,QAAQ,OAAO,cAAc,iBAAiB,OAAO,cAAc,SAAS,IAAI;CACtF,IAAI,MAAM,IAAI,WAAW,MAAM,WAAW,SAAS,aAAa,MAAM,QAAQ,gBAC5E,OAAO,OAAO,aACZ,cACA,SACA;EAAE,MAAM;EAAgB,OAAO;CAAkC,GACjE,aACF;CACF,MAAM,UAAU,OAAO,OAAO,SAAS,EAAE,KAAK,MAAM,IAAI,GAAG,YAAY;CACvE,MAAM,aAAa;EAAE,SAAS,MAAM,UAAU;EAAM,GAAG,MAAM,QAAQ,MAAM;CAAE;CAC7E,MAAM,SAAS,OAAO,QAAQ,SAAS,mBAAmB,QAAQ,WAChE,QAAQ,OAAO,cAAc;EAC3B,aAAa;EACb;EACA,GAAG,WAAW,QAAQ,MAAM;CAC9B,CAAC,CACH;CACA,MAAM,WAAW,SAAS,SAAS,MAAM,IAAI,KAAK,MAAM;CACxD,MAAM,UAAU,eAAe,UAAU,MAAM,OAAO;CACtD,MAAM,SAAS,OAAO,QAAQ,SAAS,cAAc,OAAO,WAC1D,QAAQ,OAAO,eAAe,cAAc,OAAO,GAAG;EAAE,aAAa;EAAQ;CAAW,CAAC,CAC3F;CACA,IAAI,CAAC,OAAO,MACV,OAAO,OAAO,aACZ,cACA,SACA;EAAE,MAAM;EAAmB,MAAM;CAAwB,GACzD,SACF;CACF,OAAO;EACL,GAAG,SAAS,SAAS,MAAM,IAAI,KAAK;GAAE,GAAG;GAAQ,WAAW;GAAW,GAAG;EAAO,CAAC;EAClF,GAAG,MAAM;CACX;AACF,CAAC,EACH;AACA,IAAa,kBAAb,MAAa,wBAAwB,QAAQ,QAAkD,CAAC,CAC9F,2CACF,CAAC,CAAC;CACA,OAAgB,OAAO;CACvB,OAAgB,QAAQ,MAAM,OAAO,iBAAiB,OAAO,IAAI,cAAc,IAAI,CAAC;AACtF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { providerError } from "../../internal/node/provider-errors.js";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
|
|
4
|
+
// src/providers/azure/transport.ts
|
|
5
|
+
const request = (connection, operation, mutation, call) => Effect.tryPromise({
|
|
6
|
+
try: call,
|
|
7
|
+
catch: (error) => providerError("azure", operation, mutation, error)
|
|
8
|
+
}).pipe(Effect.timeoutOrElse({
|
|
9
|
+
duration: connection.config.requestTimeoutMillis,
|
|
10
|
+
orElse: () => Effect.fail(providerError("azure", operation, mutation, void 0))
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
export { request };
|
|
14
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","names":[],"sources":["../../../src/providers/azure/transport.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport { providerError } from \"../../internal/node/provider-errors.js\";\nimport type { AzureConnection } from \"./config.js\";\n\nexport const request = <A>(\n connection: AzureConnection,\n operation: string,\n mutation: boolean,\n call: (signal: AbortSignal) => Promise<A>,\n) =>\n Effect.tryPromise({\n try: call,\n catch: (error) => providerError(\"azure\", operation, mutation, error),\n }).pipe(\n Effect.timeoutOrElse({\n duration: connection.config.requestTimeoutMillis,\n orElse: () => Effect.fail(providerError(\"azure\", operation, mutation, undefined)),\n }),\n );\n"],"mappings":";;;;AAKA,MAAa,WACX,YACA,WACA,UACA,SAEA,OAAO,WAAW;CAChB,KAAK;CACL,QAAQ,UAAU,cAAc,SAAS,WAAW,UAAU,KAAK;AACrE,CAAC,CAAC,CAAC,KACD,OAAO,cAAc;CACnB,UAAU,WAAW,OAAO;CAC5B,cAAc,OAAO,KAAK,cAAc,SAAS,WAAW,UAAU,MAAS,CAAC;AAClF,CAAC,CACH"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ObjectKey } from "../../core/object.js";
|
|
2
|
+
import { decodeRequest } from "../../internal/request-validation.js";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
// src/providers/azure/validation.ts
|
|
6
|
+
/** The SDK normalizes dot segments, so accepting them would address a different blob. */
|
|
7
|
+
const AzureKey = ObjectKey.check(Schema.makeFilter((key) => Array.from(key).length <= 1024 && !key.split("/").some((segment) => segment === "." || segment === ".."), { expected: "an Azure blob name within 1024 characters without dot segments" }));
|
|
8
|
+
const validateKey = (key, operation, mutation = false) => decodeRequest(AzureKey, key, operation, "azure", mutation);
|
|
9
|
+
|
|
10
|
+
export { AzureKey, validateKey };
|
|
11
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","names":[],"sources":["../../../src/providers/azure/validation.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nimport { ObjectKey } from \"../../core/object.js\";\nimport { decodeRequest } from \"../../internal/request-validation.js\";\n\n/** The SDK normalizes dot segments, so accepting them would address a different blob. */\nexport const AzureKey = ObjectKey.check(\n Schema.makeFilter(\n (key) =>\n Array.from(key).length <= 1024 &&\n !key.split(\"/\").some((segment) => segment === \".\" || segment === \"..\"),\n { expected: \"an Azure blob name within 1024 characters without dot segments\" },\n ),\n);\nexport const validateKey = (key: string, operation: string, mutation = false) =>\n decodeRequest(AzureKey, key, operation, \"azure\", mutation);\n"],"mappings":";;;;;;AAMA,MAAa,WAAW,UAAU,MAChC,OAAO,YACJ,QACC,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,QAC1B,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,YAAY,YAAY,OAAO,YAAY,IAAI,GACvE,EAAE,UAAU,iEAAiE,CAC/E,CACF;AACA,MAAa,eAAe,KAAa,WAAmB,WAAW,UACrE,cAAc,UAAU,KAAK,WAAW,SAAS,QAAQ"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ObjectMetadata } from "../../core/object.js";
|
|
2
|
+
import { fileError, fileSize } from "./layout.js";
|
|
3
|
+
import { Effect, Option, Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
// src/providers/filesystem/envelope.ts
|
|
6
|
+
const headerBytes = 65536;
|
|
7
|
+
const magic = new TextEncoder().encode("EFSTOR01");
|
|
8
|
+
const Envelope = Schema.fromJsonString(Schema.Struct({
|
|
9
|
+
version: Schema.Literal(1),
|
|
10
|
+
metadata: ObjectMetadata
|
|
11
|
+
}));
|
|
12
|
+
const readExactly = Effect.fnUntraced(function* (file, length, position) {
|
|
13
|
+
const bytes = new Uint8Array(length);
|
|
14
|
+
let offset = 0;
|
|
15
|
+
while (offset < length) {
|
|
16
|
+
const count = yield* file.read(bytes.subarray(offset), { position: BigInt(position + offset) });
|
|
17
|
+
if (count === 0) return yield* fileError("get", "TruncatedEnvelope");
|
|
18
|
+
offset += count;
|
|
19
|
+
}
|
|
20
|
+
return bytes;
|
|
21
|
+
});
|
|
22
|
+
const encodeEnvelope = Effect.fnUntraced(function* (metadata) {
|
|
23
|
+
const encoded = yield* Schema.encodeEffect(Envelope)({
|
|
24
|
+
version: 1,
|
|
25
|
+
metadata
|
|
26
|
+
}).pipe(Effect.mapError(() => fileError("put", "InvalidMetadata", "not-started")));
|
|
27
|
+
const bytes = new TextEncoder().encode(encoded);
|
|
28
|
+
if (bytes.length > 65524) return yield* fileError("put", "MetadataTooLarge", "not-started");
|
|
29
|
+
const header = new Uint8Array(headerBytes);
|
|
30
|
+
header.set(magic);
|
|
31
|
+
new DataView(header.buffer).setUint32(8, bytes.length);
|
|
32
|
+
header.set(bytes, 12);
|
|
33
|
+
return header;
|
|
34
|
+
});
|
|
35
|
+
const readEnvelope = Effect.fnUntraced(function* (context, file, key) {
|
|
36
|
+
const prefix = yield* readExactly(file, 12, 0);
|
|
37
|
+
if (!magic.every((byte, index) => prefix[index] === byte)) return yield* fileError("get", "InvalidEnvelope");
|
|
38
|
+
const length = new DataView(prefix.buffer).getUint32(8);
|
|
39
|
+
if (length < 1 || length > 65524) return yield* fileError("get", "InvalidEnvelope");
|
|
40
|
+
const encoded = yield* readExactly(file, length, 12);
|
|
41
|
+
const text = yield* Effect.try({
|
|
42
|
+
try: () => new TextDecoder("utf-8", { fatal: true }).decode(encoded),
|
|
43
|
+
catch: () => fileError("get", "InvalidEnvelope")
|
|
44
|
+
});
|
|
45
|
+
const { metadata } = yield* Schema.decodeUnknownEffect(Envelope)(text).pipe(Effect.mapError(() => fileError("get", "InvalidEnvelope")));
|
|
46
|
+
if (metadata.ref.storeId !== context.storeId || metadata.ref.version || key !== void 0 && metadata.ref.key !== key || metadata.size === void 0 || !metadata.etag || metadata.checksums?.length !== 1 || metadata.checksums[0]?.algorithm !== "sha256" || metadata.checksums[0]?.scope !== "full-object" || fileSize(yield* file.stat) !== BigInt(65536) + BigInt(metadata.size)) return yield* fileError("get", "InvalidEnvelope");
|
|
47
|
+
return metadata;
|
|
48
|
+
});
|
|
49
|
+
const readChunk = Effect.fnUntraced(function* (file, position, length) {
|
|
50
|
+
const bytes = yield* file.readAlloc(length, { position: BigInt(position) });
|
|
51
|
+
if (Option.isNone(bytes)) return yield* fileError("get", "TruncatedBody");
|
|
52
|
+
return bytes.value;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export { encodeEnvelope, headerBytes, readChunk, readEnvelope, readExactly };
|
|
56
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","names":[],"sources":["../../../src/providers/filesystem/envelope.ts"],"sourcesContent":["import { Effect, Option, Schema } from \"effect\";\nimport type { FileSystem } from \"effect\";\n\nimport { ObjectMetadata } from \"../../core/object.js\";\nimport { fileError, fileSize } from \"./layout.js\";\nimport type { FilesystemContext } from \"./layout.js\";\n\n// One immutable file publishes bytes and metadata together, without sidecar races.\nexport const headerBytes = 65536;\nconst magic = new TextEncoder().encode(\"EFSTOR01\");\nconst Envelope = Schema.fromJsonString(\n Schema.Struct({ version: Schema.Literal(1), metadata: ObjectMetadata }),\n);\n\nexport const readExactly = Effect.fnUntraced(function* (\n file: FileSystem.File,\n length: number,\n position: number,\n) {\n const bytes = new Uint8Array(length);\n let offset = 0;\n while (offset < length) {\n const count = yield* file.read(bytes.subarray(offset), { position: BigInt(position + offset) });\n if (count === 0) return yield* fileError(\"get\", \"TruncatedEnvelope\");\n offset += count;\n }\n return bytes;\n});\n\nexport const encodeEnvelope = Effect.fnUntraced(function* (metadata: ObjectMetadata) {\n const encoded = yield* Schema.encodeEffect(Envelope)({ version: 1, metadata }).pipe(\n Effect.mapError(() => fileError(\"put\", \"InvalidMetadata\", \"not-started\")),\n );\n const bytes = new TextEncoder().encode(encoded);\n if (bytes.length > headerBytes - 12)\n return yield* fileError(\"put\", \"MetadataTooLarge\", \"not-started\");\n const header = new Uint8Array(headerBytes);\n header.set(magic);\n new DataView(header.buffer).setUint32(8, bytes.length);\n header.set(bytes, 12);\n return header;\n});\n\nexport const readEnvelope = Effect.fnUntraced(function* (\n context: FilesystemContext,\n file: FileSystem.File,\n key?: string,\n) {\n const prefix = yield* readExactly(file, 12, 0);\n if (!magic.every((byte, index) => prefix[index] === byte))\n return yield* fileError(\"get\", \"InvalidEnvelope\");\n const length = new DataView(prefix.buffer).getUint32(8);\n if (length < 1 || length > headerBytes - 12) return yield* fileError(\"get\", \"InvalidEnvelope\");\n const encoded = yield* readExactly(file, length, 12);\n const text = yield* Effect.try({\n try: () => new TextDecoder(\"utf-8\", { fatal: true }).decode(encoded),\n catch: () => fileError(\"get\", \"InvalidEnvelope\"),\n });\n const { metadata } = yield* Schema.decodeUnknownEffect(Envelope)(text).pipe(\n Effect.mapError(() => fileError(\"get\", \"InvalidEnvelope\")),\n );\n if (\n metadata.ref.storeId !== context.storeId ||\n metadata.ref.version ||\n (key !== undefined && metadata.ref.key !== key) ||\n metadata.size === undefined ||\n !metadata.etag ||\n metadata.checksums?.length !== 1 ||\n metadata.checksums[0]?.algorithm !== \"sha256\" ||\n metadata.checksums[0]?.scope !== \"full-object\" ||\n fileSize(yield* file.stat) !== BigInt(headerBytes) + BigInt(metadata.size)\n )\n return yield* fileError(\"get\", \"InvalidEnvelope\");\n return metadata;\n});\n\nexport const readChunk = Effect.fnUntraced(function* (\n file: FileSystem.File,\n position: number,\n length: number,\n) {\n const bytes = yield* file.readAlloc(length, { position: BigInt(position) });\n if (Option.isNone(bytes)) return yield* fileError(\"get\", \"TruncatedBody\");\n return bytes.value;\n});\n"],"mappings":";;;;;AAQA,MAAa,cAAc;AAC3B,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,UAAU;AACjD,MAAM,WAAW,OAAO,eACtB,OAAO,OAAO;CAAE,SAAS,OAAO,QAAQ,CAAC;CAAG,UAAU;AAAe,CAAC,CACxE;AAEA,MAAa,cAAc,OAAO,WAAW,WAC3C,MACA,QACA,UACA;CACA,MAAM,QAAQ,IAAI,WAAW,MAAM;CACnC,IAAI,SAAS;CACb,OAAO,SAAS,QAAQ;EACtB,MAAM,QAAQ,OAAO,KAAK,KAAK,MAAM,SAAS,MAAM,GAAG,EAAE,UAAU,OAAO,WAAW,MAAM,EAAE,CAAC;EAC9F,IAAI,UAAU,GAAG,OAAO,OAAO,UAAU,OAAO,mBAAmB;EACnE,UAAU;CACZ;CACA,OAAO;AACT,CAAC;AAED,MAAa,iBAAiB,OAAO,WAAW,WAAW,UAA0B;CACnF,MAAM,UAAU,OAAO,OAAO,aAAa,QAAQ,CAAC,CAAC;EAAE,SAAS;EAAG;CAAS,CAAC,CAAC,CAAC,KAC7E,OAAO,eAAe,UAAU,OAAO,mBAAmB,aAAa,CAAC,CAC1E;CACA,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,OAAO;CAC9C,IAAI,MAAM,SAAS,OACjB,OAAO,OAAO,UAAU,OAAO,oBAAoB,aAAa;CAClE,MAAM,SAAS,IAAI,WAAW,WAAW;CACzC,OAAO,IAAI,KAAK;CAChB,IAAI,SAAS,OAAO,MAAM,CAAC,CAAC,UAAU,GAAG,MAAM,MAAM;CACrD,OAAO,IAAI,OAAO,EAAE;CACpB,OAAO;AACT,CAAC;AAED,MAAa,eAAe,OAAO,WAAW,WAC5C,SACA,MACA,KACA;CACA,MAAM,SAAS,OAAO,YAAY,MAAM,IAAI,CAAC;CAC7C,IAAI,CAAC,MAAM,OAAO,MAAM,UAAU,OAAO,WAAW,IAAI,GACtD,OAAO,OAAO,UAAU,OAAO,iBAAiB;CAClD,MAAM,SAAS,IAAI,SAAS,OAAO,MAAM,CAAC,CAAC,UAAU,CAAC;CACtD,IAAI,SAAS,KAAK,SAAS,OAAkB,OAAO,OAAO,UAAU,OAAO,iBAAiB;CAC7F,MAAM,UAAU,OAAO,YAAY,MAAM,QAAQ,EAAE;CACnD,MAAM,OAAO,OAAO,OAAO,IAAI;EAC7B,WAAW,IAAI,YAAY,SAAS,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO;EACnE,aAAa,UAAU,OAAO,iBAAiB;CACjD,CAAC;CACD,MAAM,EAAE,aAAa,OAAO,OAAO,oBAAoB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KACrE,OAAO,eAAe,UAAU,OAAO,iBAAiB,CAAC,CAC3D;CACA,IACE,SAAS,IAAI,YAAY,QAAQ,WACjC,SAAS,IAAI,WACZ,QAAQ,UAAa,SAAS,IAAI,QAAQ,OAC3C,SAAS,SAAS,UAClB,CAAC,SAAS,QACV,SAAS,WAAW,WAAW,KAC/B,SAAS,UAAU,EAAE,EAAE,cAAc,YACrC,SAAS,UAAU,EAAE,EAAE,UAAU,iBACjC,SAAS,OAAO,KAAK,IAAI,MAAM,YAAkB,IAAI,OAAO,SAAS,IAAI,GAEzE,OAAO,OAAO,UAAU,OAAO,iBAAiB;CAClD,OAAO;AACT,CAAC;AAED,MAAa,YAAY,OAAO,WAAW,WACzC,MACA,UACA,QACA;CACA,MAAM,QAAQ,OAAO,KAAK,UAAU,QAAQ,EAAE,UAAU,OAAO,QAAQ,EAAE,CAAC;CAC1E,IAAI,OAAO,OAAO,KAAK,GAAG,OAAO,OAAO,UAAU,OAAO,eAAe;CACxE,OAAO,MAAM;AACf,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { storageError } from "../../core/errors.js";
|
|
2
|
+
import { syncDirectory } from "../../runtime/filesystem.js";
|
|
3
|
+
import { ByteSize, Effect, Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
// src/providers/filesystem/identity.ts
|
|
6
|
+
const Identity = Schema.fromJsonString(Schema.Struct({
|
|
7
|
+
version: Schema.Literal(1),
|
|
8
|
+
storeId: Schema.NonEmptyString,
|
|
9
|
+
id: Schema.NonEmptyString
|
|
10
|
+
}));
|
|
11
|
+
/** A root is bound to one format/store identity; reopening with another identity fails closed. */
|
|
12
|
+
const invalid = () => storageError("make", "filesystem", {
|
|
13
|
+
_tag: "InvalidConfiguration",
|
|
14
|
+
field: "root.identity"
|
|
15
|
+
});
|
|
16
|
+
const initializeIdentity = Effect.fnUntraced(function* (fs, path, root, storeId, random) {
|
|
17
|
+
const filename = path.join(root, "format.json");
|
|
18
|
+
if (!(yield* fs.exists(filename))) {
|
|
19
|
+
if ((yield* fs.readDirectory(root)).some((name) => name !== "objects" && name !== "staging" && name !== "format.json") || (yield* fs.readDirectory(path.join(root, "objects"))).length) {
|
|
20
|
+
if (!(yield* fs.exists(filename))) return yield* invalid();
|
|
21
|
+
}
|
|
22
|
+
const temporary = path.join(root, "staging", `upload-${yield* random.uuidV4()}.pending`);
|
|
23
|
+
const encoded = Schema.encodeSync(Identity)({
|
|
24
|
+
version: 1,
|
|
25
|
+
storeId,
|
|
26
|
+
id: yield* random.uuidV4()
|
|
27
|
+
});
|
|
28
|
+
yield* Effect.acquireUseRelease(Effect.succeed(temporary), () => Effect.gen(function* () {
|
|
29
|
+
yield* Effect.scoped(Effect.gen(function* () {
|
|
30
|
+
const file = yield* fs.open(temporary, {
|
|
31
|
+
flag: "wx",
|
|
32
|
+
mode: 384,
|
|
33
|
+
noFollow: true
|
|
34
|
+
});
|
|
35
|
+
yield* file.writeAll(new TextEncoder().encode(encoded));
|
|
36
|
+
yield* file.sync;
|
|
37
|
+
}));
|
|
38
|
+
yield* fs.link(temporary, filename).pipe(Effect.catchReason("PlatformError", "AlreadyExists", () => Effect.void));
|
|
39
|
+
yield* syncDirectory(fs, root);
|
|
40
|
+
}), () => fs.remove(temporary, { force: true }).pipe(Effect.orDie)).pipe(Effect.uninterruptible);
|
|
41
|
+
}
|
|
42
|
+
const identity = yield* Effect.scoped(Effect.gen(function* () {
|
|
43
|
+
if ((yield* fs.lstat(filename)).type !== "File") return yield* invalid();
|
|
44
|
+
const file = yield* fs.open(filename, {
|
|
45
|
+
flag: "r",
|
|
46
|
+
noFollow: true
|
|
47
|
+
});
|
|
48
|
+
const length = Number(ByteSize.toBigInt((yield* file.stat).size));
|
|
49
|
+
if (length < 1 || length > 16384) return yield* invalid();
|
|
50
|
+
const bytes = new Uint8Array(length);
|
|
51
|
+
let offset = 0;
|
|
52
|
+
while (offset < length) {
|
|
53
|
+
const count = yield* file.read(bytes.subarray(offset));
|
|
54
|
+
if (count === 0) return yield* invalid();
|
|
55
|
+
offset += count;
|
|
56
|
+
}
|
|
57
|
+
const text = yield* Effect.try({
|
|
58
|
+
try: () => new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
59
|
+
catch: invalid
|
|
60
|
+
});
|
|
61
|
+
return yield* Schema.decodeUnknownEffect(Identity)(text).pipe(Effect.mapError(invalid));
|
|
62
|
+
}));
|
|
63
|
+
if (identity.storeId !== storeId) return yield* invalid();
|
|
64
|
+
return identity.id;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export { initializeIdentity };
|
|
68
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","names":[],"sources":["../../../src/providers/filesystem/identity.ts"],"sourcesContent":["import { ByteSize, Effect, Schema } from \"effect\";\nimport type { FileSystem, Path } from \"effect\";\nimport type { SecureRandom } from \"effect/crypto\";\n\nimport { storageError } from \"../../core/errors.js\";\nimport { syncDirectory } from \"../../runtime/filesystem.js\";\n\nconst Identity = Schema.fromJsonString(\n Schema.Struct({\n version: Schema.Literal(1),\n storeId: Schema.NonEmptyString,\n id: Schema.NonEmptyString,\n }),\n);\n\n/** A root is bound to one format/store identity; reopening with another identity fails closed. */\nconst invalid = () =>\n storageError(\"make\", \"filesystem\", { _tag: \"InvalidConfiguration\", field: \"root.identity\" });\n\nexport const initializeIdentity = Effect.fnUntraced(function* (\n fs: FileSystem.FileSystem,\n path: Path.Path,\n root: string,\n storeId: string,\n random: SecureRandom.SecureRandom[\"Service\"],\n) {\n const filename = path.join(root, \"format.json\");\n if (!(yield* fs.exists(filename))) {\n const names = yield* fs.readDirectory(root);\n if (\n names.some((name) => name !== \"objects\" && name !== \"staging\" && name !== \"format.json\") ||\n (yield* fs.readDirectory(path.join(root, \"objects\"))).length\n ) {\n if (!(yield* fs.exists(filename))) return yield* invalid();\n }\n const temporary = path.join(root, \"staging\", `upload-${yield* random.uuidV4()}.pending`);\n const encoded = Schema.encodeSync(Identity)({\n version: 1,\n storeId,\n id: yield* random.uuidV4(),\n });\n yield* Effect.acquireUseRelease(\n Effect.succeed(temporary),\n () =>\n Effect.gen(function* () {\n yield* Effect.scoped(\n Effect.gen(function* () {\n const file = yield* fs.open(temporary, { flag: \"wx\", mode: 0o600, noFollow: true });\n yield* file.writeAll(new TextEncoder().encode(encoded));\n yield* file.sync;\n }),\n );\n yield* fs\n .link(temporary, filename)\n .pipe(Effect.catchReason(\"PlatformError\", \"AlreadyExists\", () => Effect.void));\n yield* syncDirectory(fs, root);\n }),\n () => fs.remove(temporary, { force: true }).pipe(Effect.orDie),\n ).pipe(Effect.uninterruptible);\n }\n const identity = yield* Effect.scoped(\n Effect.gen(function* () {\n if ((yield* fs.lstat(filename)).type !== \"File\") return yield* invalid();\n const file = yield* fs.open(filename, { flag: \"r\", noFollow: true });\n const length = Number(ByteSize.toBigInt((yield* file.stat).size));\n if (length < 1 || length > 16384) return yield* invalid();\n const bytes = new Uint8Array(length);\n let offset = 0;\n while (offset < length) {\n const count = yield* file.read(bytes.subarray(offset));\n if (count === 0) return yield* invalid();\n offset += count;\n }\n const text = yield* Effect.try({\n try: () => new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes),\n catch: invalid,\n });\n return yield* Schema.decodeUnknownEffect(Identity)(text).pipe(Effect.mapError(invalid));\n }),\n );\n if (identity.storeId !== storeId) return yield* invalid();\n return identity.id;\n});\n"],"mappings":";;;;;AAOA,MAAM,WAAW,OAAO,eACtB,OAAO,OAAO;CACZ,SAAS,OAAO,QAAQ,CAAC;CACzB,SAAS,OAAO;CAChB,IAAI,OAAO;AACb,CAAC,CACH;;AAGA,MAAM,gBACJ,aAAa,QAAQ,cAAc;CAAE,MAAM;CAAwB,OAAO;AAAgB,CAAC;AAE7F,MAAa,qBAAqB,OAAO,WAAW,WAClD,IACA,MACA,MACA,SACA,QACA;CACA,MAAM,WAAW,KAAK,KAAK,MAAM,aAAa;CAC9C,IAAI,EAAE,OAAO,GAAG,OAAO,QAAQ,IAAI;EAEjC,KACE,OAFmB,GAAG,cAAc,IAAI,EAEnC,CAAC,MAAM,SAAS,SAAS,aAAa,SAAS,aAAa,SAAS,aAAa,MACtF,OAAO,GAAG,cAAc,KAAK,KAAK,MAAM,SAAS,CAAC,EAAC,CAAE,QAEtD;OAAI,EAAE,OAAO,GAAG,OAAO,QAAQ,IAAI,OAAO,OAAO,QAAQ;EAAC;EAE5D,MAAM,YAAY,KAAK,KAAK,MAAM,WAAW,UAAU,OAAO,OAAO,OAAO,EAAE,SAAS;EACvF,MAAM,UAAU,OAAO,WAAW,QAAQ,CAAC,CAAC;GAC1C,SAAS;GACT;GACA,IAAI,OAAO,OAAO,OAAO;EAC3B,CAAC;EACD,OAAO,OAAO,kBACZ,OAAO,QAAQ,SAAS,SAEtB,OAAO,IAAI,aAAa;GACtB,OAAO,OAAO,OACZ,OAAO,IAAI,aAAa;IACtB,MAAM,OAAO,OAAO,GAAG,KAAK,WAAW;KAAE,MAAM;KAAM,MAAM;KAAO,UAAU;IAAK,CAAC;IAClF,OAAO,KAAK,SAAS,IAAI,YAAY,CAAC,CAAC,OAAO,OAAO,CAAC;IACtD,OAAO,KAAK;GACd,CAAC,CACH;GACA,OAAO,GACJ,KAAK,WAAW,QAAQ,CAAC,CACzB,KAAK,OAAO,YAAY,iBAAiB,uBAAuB,OAAO,IAAI,CAAC;GAC/E,OAAO,cAAc,IAAI,IAAI;EAC/B,CAAC,SACG,GAAG,OAAO,WAAW,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,CAC/D,CAAC,CAAC,KAAK,OAAO,eAAe;CAC/B;CACA,MAAM,WAAW,OAAO,OAAO,OAC7B,OAAO,IAAI,aAAa;EACtB,KAAK,OAAO,GAAG,MAAM,QAAQ,EAAC,CAAE,SAAS,QAAQ,OAAO,OAAO,QAAQ;EACvE,MAAM,OAAO,OAAO,GAAG,KAAK,UAAU;GAAE,MAAM;GAAK,UAAU;EAAK,CAAC;EACnE,MAAM,SAAS,OAAO,SAAS,UAAU,OAAO,KAAK,KAAI,CAAE,IAAI,CAAC;EAChE,IAAI,SAAS,KAAK,SAAS,OAAO,OAAO,OAAO,QAAQ;EACxD,MAAM,QAAQ,IAAI,WAAW,MAAM;EACnC,IAAI,SAAS;EACb,OAAO,SAAS,QAAQ;GACtB,MAAM,QAAQ,OAAO,KAAK,KAAK,MAAM,SAAS,MAAM,CAAC;GACrD,IAAI,UAAU,GAAG,OAAO,OAAO,QAAQ;GACvC,UAAU;EACZ;EACA,MAAM,OAAO,OAAO,OAAO,IAAI;GAC7B,WAAW,IAAI,YAAY,SAAS,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK;GACjE,OAAO;EACT,CAAC;EACD,OAAO,OAAO,OAAO,oBAAoB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO,SAAS,OAAO,CAAC;CACxF,CAAC,CACH;CACA,IAAI,SAAS,YAAY,SAAS,OAAO,OAAO,QAAQ;CACxD,OAAO,SAAS;AAClB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import "../../core/errors.js";
|
|
2
|
+
import "../../index.js";
|
|
3
|
+
import "../../transfers/models.js";
|
|
4
|
+
import "../../transfers/dependencies.js";
|
|
5
|
+
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
6
|
+
import { Digest, SecureRandom } from "effect/crypto";
|
|
7
|
+
import { PlatformError } from "effect/PlatformError";
|
|
8
|
+
export declare const FilesystemOptions: Schema.Struct<{
|
|
9
|
+
readonly root: Schema.NonEmptyString;
|
|
10
|
+
readonly storeId: Schema.NonEmptyString;
|
|
11
|
+
readonly maxObjectBytes: Schema.optional<Schema.Natural>;
|
|
12
|
+
readonly maxListEntries: Schema.optional<Schema.Int>;
|
|
13
|
+
}>;
|
|
14
|
+
export type FilesystemOptions = typeof FilesystemOptions.Type;
|
|
15
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { storageError } from "../../core/errors.js";
|
|
2
|
+
import { TransferHash } from "../../transfers/dependencies.js";
|
|
3
|
+
import { syncDirectory } from "../../runtime/filesystem.js";
|
|
4
|
+
import { initializeIdentity } from "./identity.js";
|
|
5
|
+
import { ByteSize, Effect, FileSystem, Path, Schema } from "effect";
|
|
6
|
+
import { Digest, SecureRandom } from "effect/crypto";
|
|
7
|
+
|
|
8
|
+
// src/providers/filesystem/layout.ts
|
|
9
|
+
const FilesystemOptions = Schema.Struct({
|
|
10
|
+
root: Schema.NonEmptyString,
|
|
11
|
+
storeId: Schema.NonEmptyString,
|
|
12
|
+
maxObjectBytes: Schema.optional(Schema.Natural.check(Schema.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER - 65536))),
|
|
13
|
+
maxListEntries: Schema.optional(Schema.Int.check(Schema.isBetween({
|
|
14
|
+
minimum: 1,
|
|
15
|
+
maximum: 1e6
|
|
16
|
+
})))
|
|
17
|
+
});
|
|
18
|
+
const fileError = (operation, code, outcome = "not-applicable") => storageError(operation, "filesystem", {
|
|
19
|
+
_tag: "ProviderFailure",
|
|
20
|
+
code
|
|
21
|
+
}, outcome);
|
|
22
|
+
const mapIO = (operation, outcome = "not-applicable") => (error) => {
|
|
23
|
+
const reason = error.reason._tag;
|
|
24
|
+
return storageError(operation, "filesystem", reason === "NotFound" ? { _tag: "NotFound" } : reason === "PermissionDenied" ? { _tag: "AccessDenied" } : {
|
|
25
|
+
_tag: "ProviderFailure",
|
|
26
|
+
code: reason
|
|
27
|
+
}, outcome);
|
|
28
|
+
};
|
|
29
|
+
const makeLayout = Effect.fnUntraced(function* (options) {
|
|
30
|
+
const input = yield* Schema.decodeUnknownEffect(FilesystemOptions, { onExcessProperty: "error" })(options).pipe(Effect.mapError(() => storageError("make", "filesystem", {
|
|
31
|
+
_tag: "InvalidConfiguration",
|
|
32
|
+
field: "options"
|
|
33
|
+
})));
|
|
34
|
+
const fs = yield* FileSystem.FileSystem;
|
|
35
|
+
const path = yield* Path.Path;
|
|
36
|
+
const identities = yield* Digest.Digest;
|
|
37
|
+
const random = yield* SecureRandom.SecureRandom;
|
|
38
|
+
const hash = yield* TransferHash;
|
|
39
|
+
if (hash.algorithm !== "sha256") return yield* storageError("make", "filesystem", {
|
|
40
|
+
_tag: "InvalidConfiguration",
|
|
41
|
+
field: "TransferHash.algorithm"
|
|
42
|
+
});
|
|
43
|
+
const assertDirectory = Effect.fnUntraced(function* (directory) {
|
|
44
|
+
if ((yield* fs.lstat(directory)).type !== "Directory") return yield* fileError("filesystem.directory", "UnsafeDirectory");
|
|
45
|
+
});
|
|
46
|
+
const suppliedRoot = path.resolve(input.root);
|
|
47
|
+
if (yield* fs.exists(suppliedRoot)) yield* assertDirectory(suppliedRoot);
|
|
48
|
+
const missing = [];
|
|
49
|
+
let ancestor = suppliedRoot;
|
|
50
|
+
while (!(yield* fs.exists(ancestor))) {
|
|
51
|
+
missing.push(ancestor);
|
|
52
|
+
if (path.dirname(ancestor) === ancestor) break;
|
|
53
|
+
ancestor = path.dirname(ancestor);
|
|
54
|
+
}
|
|
55
|
+
yield* fs.makeDirectory(suppliedRoot, {
|
|
56
|
+
recursive: true,
|
|
57
|
+
mode: 448
|
|
58
|
+
}).pipe(Effect.mapError(mapIO("make")));
|
|
59
|
+
for (const created of missing) yield* syncDirectory(fs, created).pipe(Effect.mapError(mapIO("make")));
|
|
60
|
+
if (missing.length) yield* syncDirectory(fs, ancestor).pipe(Effect.mapError(mapIO("make")));
|
|
61
|
+
const root = yield* fs.realPath(suppliedRoot).pipe(Effect.mapError(mapIO("make")));
|
|
62
|
+
const objects = path.join(root, "objects");
|
|
63
|
+
const staging = path.join(root, "staging");
|
|
64
|
+
for (const directory of [objects, staging]) {
|
|
65
|
+
yield* fs.makeDirectory(directory, { mode: 448 }).pipe(Effect.catchReason("PlatformError", "AlreadyExists", () => Effect.void), Effect.mapError(mapIO("make")));
|
|
66
|
+
yield* assertDirectory(directory).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("make")(error) : error));
|
|
67
|
+
}
|
|
68
|
+
yield* syncDirectory(fs, root).pipe(Effect.mapError(mapIO("make")));
|
|
69
|
+
const rootId = yield* initializeIdentity(fs, path, root, input.storeId, random);
|
|
70
|
+
const checkDirectories = Effect.all([
|
|
71
|
+
assertDirectory(root),
|
|
72
|
+
assertDirectory(objects),
|
|
73
|
+
assertDirectory(staging)
|
|
74
|
+
], { discard: true }).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("filesystem.directory")(error) : error));
|
|
75
|
+
const objectFilename = (key) => identities.digestHex(Digest.sha256, new TextEncoder().encode(key)).pipe(Effect.map((digest) => path.join(objects, `${digest}.object`)));
|
|
76
|
+
const regularFile = Effect.fnUntraced(function* (filename) {
|
|
77
|
+
const info = yield* fs.lstat(filename);
|
|
78
|
+
if (info.type !== "File") return yield* fileError("filesystem.open", "UnsafeObject");
|
|
79
|
+
return info;
|
|
80
|
+
});
|
|
81
|
+
const open = Effect.fnUntraced(function* (filename) {
|
|
82
|
+
yield* checkDirectories;
|
|
83
|
+
yield* regularFile(filename);
|
|
84
|
+
const file = yield* fs.open(filename, {
|
|
85
|
+
flag: "r",
|
|
86
|
+
noFollow: true
|
|
87
|
+
});
|
|
88
|
+
if ((yield* file.stat).type !== "File") return yield* fileError("filesystem.open", "UnsafeObject");
|
|
89
|
+
return file;
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
fs,
|
|
93
|
+
path,
|
|
94
|
+
root,
|
|
95
|
+
rootId,
|
|
96
|
+
objects,
|
|
97
|
+
staging,
|
|
98
|
+
storeId: input.storeId,
|
|
99
|
+
random,
|
|
100
|
+
hash,
|
|
101
|
+
filename: objectFilename,
|
|
102
|
+
open,
|
|
103
|
+
regularFile,
|
|
104
|
+
checkDirectories,
|
|
105
|
+
maxObjectBytes: input.maxObjectBytes ?? 1073741824,
|
|
106
|
+
maxListEntries: input.maxListEntries ?? 1e4
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
const fileSize = (info) => ByteSize.toBigInt(info.size);
|
|
110
|
+
|
|
111
|
+
export { FilesystemOptions, fileError, fileSize, makeLayout, mapIO };
|
|
112
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","names":[],"sources":["../../../src/providers/filesystem/layout.ts"],"sourcesContent":["import { ByteSize, Effect, FileSystem, Path, Schema } from \"effect\";\nimport { Digest, SecureRandom } from \"effect/crypto\";\nimport type { PlatformError } from \"effect/PlatformError\";\n\nimport { storageError } from \"../../core/errors.js\";\nimport type { MutationOutcome } from \"../../core/errors.js\";\nimport { syncDirectory } from \"../../runtime/filesystem.js\";\nimport { TransferHash } from \"../../transfers/dependencies.js\";\nimport { initializeIdentity } from \"./identity.js\";\n\nexport const FilesystemOptions = Schema.Struct({\n root: Schema.NonEmptyString,\n storeId: Schema.NonEmptyString,\n maxObjectBytes: Schema.optional(\n Schema.Natural.check(Schema.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER - 65536)),\n ),\n maxListEntries: Schema.optional(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 1000000 })),\n ),\n});\nexport type FilesystemOptions = typeof FilesystemOptions.Type;\n\nexport const fileError = (\n operation: string,\n code: string,\n outcome: MutationOutcome = \"not-applicable\",\n) => storageError(operation, \"filesystem\", { _tag: \"ProviderFailure\", code }, outcome);\n\nexport const mapIO =\n (operation: string, outcome: MutationOutcome = \"not-applicable\") =>\n (error: PlatformError) => {\n const reason = error.reason._tag;\n return storageError(\n operation,\n \"filesystem\",\n reason === \"NotFound\"\n ? { _tag: \"NotFound\" }\n : reason === \"PermissionDenied\"\n ? { _tag: \"AccessDenied\" }\n : { _tag: \"ProviderFailure\", code: reason },\n outcome,\n );\n };\n\nexport const makeLayout = Effect.fnUntraced(function* (options: FilesystemOptions) {\n const input = yield* Schema.decodeUnknownEffect(FilesystemOptions, { onExcessProperty: \"error\" })(\n options,\n ).pipe(\n Effect.mapError(() =>\n storageError(\"make\", \"filesystem\", { _tag: \"InvalidConfiguration\", field: \"options\" }),\n ),\n );\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const identities = yield* Digest.Digest;\n const random = yield* SecureRandom.SecureRandom;\n const hash = yield* TransferHash;\n if (hash.algorithm !== \"sha256\")\n return yield* storageError(\"make\", \"filesystem\", {\n _tag: \"InvalidConfiguration\",\n field: \"TransferHash.algorithm\",\n });\n\n const assertDirectory = Effect.fnUntraced(function* (directory: string) {\n const info = yield* fs.lstat(directory);\n if (info.type !== \"Directory\")\n return yield* fileError(\"filesystem.directory\", \"UnsafeDirectory\");\n });\n const suppliedRoot = path.resolve(input.root);\n if (yield* fs.exists(suppliedRoot)) yield* assertDirectory(suppliedRoot);\n const missing: string[] = [];\n let ancestor = suppliedRoot;\n while (!(yield* fs.exists(ancestor))) {\n missing.push(ancestor);\n if (path.dirname(ancestor) === ancestor) break;\n ancestor = path.dirname(ancestor);\n }\n yield* fs\n .makeDirectory(suppliedRoot, { recursive: true, mode: 0o700 })\n .pipe(Effect.mapError(mapIO(\"make\")));\n for (const created of missing)\n yield* syncDirectory(fs, created).pipe(Effect.mapError(mapIO(\"make\")));\n if (missing.length) yield* syncDirectory(fs, ancestor).pipe(Effect.mapError(mapIO(\"make\")));\n const root = yield* fs.realPath(suppliedRoot).pipe(Effect.mapError(mapIO(\"make\")));\n const objects = path.join(root, \"objects\");\n const staging = path.join(root, \"staging\");\n for (const directory of [objects, staging]) {\n yield* fs.makeDirectory(directory, { mode: 0o700 }).pipe(\n Effect.catchReason(\"PlatformError\", \"AlreadyExists\", () => Effect.void),\n Effect.mapError(mapIO(\"make\")),\n );\n yield* assertDirectory(directory).pipe(\n Effect.mapError((error) => (error._tag === \"PlatformError\" ? mapIO(\"make\")(error) : error)),\n );\n }\n yield* syncDirectory(fs, root).pipe(Effect.mapError(mapIO(\"make\")));\n\n const rootId = yield* initializeIdentity(fs, path, root, input.storeId, random);\n\n const checkDirectories = Effect.all(\n [assertDirectory(root), assertDirectory(objects), assertDirectory(staging)],\n { discard: true },\n ).pipe(\n Effect.mapError((error) =>\n error._tag === \"PlatformError\" ? mapIO(\"filesystem.directory\")(error) : error,\n ),\n );\n const objectFilename = (key: string) =>\n identities\n .digestHex(Digest.sha256, new TextEncoder().encode(key))\n .pipe(Effect.map((digest) => path.join(objects, `${digest}.object`)));\n const regularFile = Effect.fnUntraced(function* (filename: string) {\n const info = yield* fs.lstat(filename);\n if (info.type !== \"File\") return yield* fileError(\"filesystem.open\", \"UnsafeObject\");\n return info;\n });\n const open = Effect.fnUntraced(function* (filename: string) {\n yield* checkDirectories;\n yield* regularFile(filename);\n const file = yield* fs.open(filename, { flag: \"r\", noFollow: true });\n if ((yield* file.stat).type !== \"File\")\n return yield* fileError(\"filesystem.open\", \"UnsafeObject\");\n return file;\n });\n\n return {\n fs,\n path,\n root,\n rootId,\n objects,\n staging,\n storeId: input.storeId,\n random,\n hash,\n filename: objectFilename,\n open,\n regularFile,\n checkDirectories,\n maxObjectBytes: input.maxObjectBytes ?? 1024 * 1024 * 1024,\n maxListEntries: input.maxListEntries ?? 10000,\n };\n});\nexport type FilesystemContext = Effect.Success<ReturnType<typeof makeLayout>>;\nexport const fileSize = (info: FileSystem.File.Info) => ByteSize.toBigInt(info.size);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { storageError } from "../../core/errors.js";
|
|
2
|
+
import { mapIO } from "./layout.js";
|
|
3
|
+
import { readEnvelope } from "./envelope.js";
|
|
4
|
+
import { Effect, Schema } from "effect";
|
|
5
|
+
import { Base64Url } from "effect/encoding";
|
|
6
|
+
|
|
7
|
+
// src/providers/filesystem/list.ts
|
|
8
|
+
const Cursor = Schema.fromJsonString(Schema.Struct({
|
|
9
|
+
version: Schema.Literal(1),
|
|
10
|
+
root: Schema.String,
|
|
11
|
+
storeId: Schema.String,
|
|
12
|
+
prefix: Schema.String,
|
|
13
|
+
delimiter: Schema.NullOr(Schema.String),
|
|
14
|
+
limit: Schema.Natural,
|
|
15
|
+
after: Schema.String
|
|
16
|
+
}));
|
|
17
|
+
const invalid = () => storageError("listPage", "filesystem", {
|
|
18
|
+
_tag: "InvalidInput",
|
|
19
|
+
field: "cursor"
|
|
20
|
+
});
|
|
21
|
+
const list = Effect.fnUntraced(function* (context, request = {}) {
|
|
22
|
+
const { prefix = "", delimiter, limit = 100 } = request;
|
|
23
|
+
let after;
|
|
24
|
+
if (request.cursor) {
|
|
25
|
+
if (request.cursor.length > 32768) return yield* invalid();
|
|
26
|
+
const text = yield* Effect.fromResult(Base64Url.decodeString(request.cursor)).pipe(Effect.mapError(invalid));
|
|
27
|
+
const cursor = yield* Schema.decodeUnknownEffect(Cursor)(text).pipe(Effect.mapError(invalid));
|
|
28
|
+
if (cursor.root !== context.rootId || cursor.storeId !== context.storeId || cursor.prefix !== prefix || cursor.delimiter !== (delimiter ?? null) || cursor.limit !== limit) return yield* invalid();
|
|
29
|
+
after = cursor.after;
|
|
30
|
+
}
|
|
31
|
+
yield* context.checkDirectories;
|
|
32
|
+
const names = yield* context.fs.readDirectory(context.objects).pipe(Effect.mapError(mapIO("listPage")));
|
|
33
|
+
if (names.length > context.maxListEntries) return yield* storageError("listPage", "filesystem", {
|
|
34
|
+
_tag: "LimitExceeded",
|
|
35
|
+
limit: context.maxListEntries
|
|
36
|
+
});
|
|
37
|
+
const entries = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const name of names) {
|
|
39
|
+
if (!/^[a-f0-9]{64}\.object$/u.test(name)) continue;
|
|
40
|
+
const filename = context.path.join(context.objects, name);
|
|
41
|
+
const metadata = yield* Effect.scoped(Effect.gen(function* () {
|
|
42
|
+
const file = yield* context.open(filename);
|
|
43
|
+
const saved = yield* readEnvelope(context, file);
|
|
44
|
+
if ((yield* context.filename(saved.ref.key)) !== filename) return yield* invalid();
|
|
45
|
+
return saved;
|
|
46
|
+
})).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("listPage")(error) : error), Effect.catchReason("StorageError", "NotFound", () => Effect.undefined));
|
|
47
|
+
if (!metadata || !metadata.ref.key.startsWith(prefix)) continue;
|
|
48
|
+
const key = metadata.ref.key;
|
|
49
|
+
const index = delimiter ? key.indexOf(delimiter, prefix.length) : -1;
|
|
50
|
+
if (delimiter && index >= 0) {
|
|
51
|
+
const common = key.slice(0, index + delimiter.length);
|
|
52
|
+
entries.set(common, {
|
|
53
|
+
_tag: "CommonPrefix",
|
|
54
|
+
prefix: common
|
|
55
|
+
});
|
|
56
|
+
} else entries.set(key, {
|
|
57
|
+
_tag: "Object",
|
|
58
|
+
metadata
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const sorted = [...entries.keys()].toSorted().filter((key) => after === void 0 || key > after);
|
|
62
|
+
const keys = sorted.slice(0, limit);
|
|
63
|
+
const last = keys.at(-1);
|
|
64
|
+
return {
|
|
65
|
+
entries: keys.flatMap((key) => {
|
|
66
|
+
const entry = entries.get(key);
|
|
67
|
+
return entry ? [entry] : [];
|
|
68
|
+
}),
|
|
69
|
+
...last !== void 0 && sorted.length > limit ? { cursor: Base64Url.encode(Schema.encodeSync(Cursor)({
|
|
70
|
+
version: 1,
|
|
71
|
+
root: context.rootId,
|
|
72
|
+
storeId: context.storeId,
|
|
73
|
+
prefix,
|
|
74
|
+
delimiter: delimiter ?? null,
|
|
75
|
+
limit,
|
|
76
|
+
after: last
|
|
77
|
+
})) } : {}
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export { list };
|
|
82
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","names":[],"sources":["../../../src/providers/filesystem/list.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\nimport { Base64Url } from \"effect/encoding\";\n\nimport type { StorageError } from \"../../core/errors.js\";\nimport { storageError } from \"../../core/errors.js\";\nimport type { ListEntry, ListPage, ListRequest } from \"../../core/requests.js\";\nimport { readEnvelope } from \"./envelope.js\";\nimport { mapIO } from \"./layout.js\";\nimport type { FilesystemContext } from \"./layout.js\";\n\nconst Cursor = Schema.fromJsonString(\n Schema.Struct({\n version: Schema.Literal(1),\n root: Schema.String,\n storeId: Schema.String,\n prefix: Schema.String,\n delimiter: Schema.NullOr(Schema.String),\n limit: Schema.Natural,\n after: Schema.String,\n }),\n);\n\nconst invalid = () =>\n storageError(\"listPage\", \"filesystem\", { _tag: \"InvalidInput\", field: \"cursor\" });\n\nexport const list = Effect.fnUntraced(function* (\n context: FilesystemContext,\n request: ListRequest = {},\n): Effect.fn.Return<ListPage, StorageError> {\n const { prefix = \"\", delimiter, limit = 100 } = request;\n let after: string | undefined;\n if (request.cursor) {\n if (request.cursor.length > 32768) return yield* invalid();\n const text = yield* Effect.fromResult(Base64Url.decodeString(request.cursor)).pipe(\n Effect.mapError(invalid),\n );\n const cursor = yield* Schema.decodeUnknownEffect(Cursor)(text).pipe(Effect.mapError(invalid));\n if (\n cursor.root !== context.rootId ||\n cursor.storeId !== context.storeId ||\n cursor.prefix !== prefix ||\n cursor.delimiter !== (delimiter ?? null) ||\n cursor.limit !== limit\n )\n return yield* invalid();\n after = cursor.after;\n }\n yield* context.checkDirectories;\n // readDirectory allocates an array. This profile deliberately documents O(directory) scans.\n const names = yield* context.fs\n .readDirectory(context.objects)\n .pipe(Effect.mapError(mapIO(\"listPage\")));\n if (names.length > context.maxListEntries)\n return yield* storageError(\"listPage\", \"filesystem\", {\n _tag: \"LimitExceeded\",\n limit: context.maxListEntries,\n });\n const entries = new Map<string, ListEntry>();\n for (const name of names) {\n if (!/^[a-f0-9]{64}\\.object$/u.test(name)) continue;\n const filename = context.path.join(context.objects, name);\n const metadata = yield* Effect.scoped(\n Effect.gen(function* () {\n const file = yield* context.open(filename);\n const saved = yield* readEnvelope(context, file);\n if ((yield* context.filename(saved.ref.key)) !== filename) return yield* invalid();\n return saved;\n }),\n ).pipe(\n Effect.mapError((error) =>\n error._tag === \"PlatformError\" ? mapIO(\"listPage\")(error) : error,\n ),\n Effect.catchReason(\"StorageError\", \"NotFound\", () => Effect.undefined),\n );\n if (!metadata || !metadata.ref.key.startsWith(prefix)) continue;\n const key = metadata.ref.key;\n const index = delimiter ? key.indexOf(delimiter, prefix.length) : -1;\n if (delimiter && index >= 0) {\n const common = key.slice(0, index + delimiter.length);\n entries.set(common, { _tag: \"CommonPrefix\", prefix: common });\n } else entries.set(key, { _tag: \"Object\", metadata });\n }\n const sorted = [...entries.keys()].toSorted().filter((key) => after === undefined || key > after);\n const keys = sorted.slice(0, limit);\n const last = keys.at(-1);\n return {\n entries: keys.flatMap((key) => {\n const entry = entries.get(key);\n return entry ? [entry] : [];\n }),\n ...(last !== undefined && sorted.length > limit\n ? {\n cursor: Base64Url.encode(\n Schema.encodeSync(Cursor)({\n version: 1,\n root: context.rootId,\n storeId: context.storeId,\n prefix,\n delimiter: delimiter ?? null,\n limit,\n after: last,\n }),\n ),\n }\n : {}),\n };\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { storageError } from "../../core/errors.js";
|
|
2
|
+
import { resolveRange } from "../../core/ranges.js";
|
|
3
|
+
import { syncDirectory } from "../../runtime/filesystem.js";
|
|
4
|
+
import { mapIO } from "./layout.js";
|
|
5
|
+
import { encodeEnvelope, headerBytes, readChunk, readEnvelope } from "./envelope.js";
|
|
6
|
+
import { Cause, DateTime, Effect, Predicate, Stream } from "effect";
|
|
7
|
+
|
|
8
|
+
// src/providers/filesystem/operations.ts
|
|
9
|
+
const head = Effect.fnUntraced(function* (context, request) {
|
|
10
|
+
const key = "ref" in request ? request.ref.key : request.key;
|
|
11
|
+
return yield* Effect.scoped(Effect.gen(function* () {
|
|
12
|
+
const file = yield* context.open(yield* context.filename(key));
|
|
13
|
+
return yield* readEnvelope(context, file, key);
|
|
14
|
+
})).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("head")(error) : error));
|
|
15
|
+
});
|
|
16
|
+
const get = Effect.fnUntraced(function* (context, request) {
|
|
17
|
+
const key = "ref" in request ? request.ref.key : request.key;
|
|
18
|
+
const file = yield* context.open(yield* context.filename(key)).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("get")(error) : error));
|
|
19
|
+
const metadata = yield* readEnvelope(context, file, key).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("get")(error) : error));
|
|
20
|
+
if (request.condition?._tag === "IfMatch" && request.condition.etag !== "*" && request.condition.etag !== metadata.etag) return yield* storageError("get", "filesystem", { _tag: "PreconditionFailed" });
|
|
21
|
+
if (request.condition?._tag === "IfNoneMatch" && (request.condition.etag === "*" || request.condition.etag === metadata.etag)) return {
|
|
22
|
+
_tag: "NotModified",
|
|
23
|
+
metadata
|
|
24
|
+
};
|
|
25
|
+
const size = metadata.size ?? 0;
|
|
26
|
+
const range = request.range ? yield* Effect.fromResult(resolveRange(request.range, size, "filesystem")) : void 0;
|
|
27
|
+
const start = range?.start ?? 0;
|
|
28
|
+
const length = range ? range.end - range.start + 1 : size;
|
|
29
|
+
let offset = 0;
|
|
30
|
+
return {
|
|
31
|
+
_tag: "Object",
|
|
32
|
+
metadata,
|
|
33
|
+
body: Stream.fromPull(Effect.succeed(Effect.gen(function* () {
|
|
34
|
+
if (offset >= length) return yield* Cause.done();
|
|
35
|
+
const bytes = yield* readChunk(file, headerBytes + start + offset, Math.min(65536, length - offset)).pipe(Effect.mapError((error) => error._tag === "PlatformError" ? mapIO("get")(error) : error));
|
|
36
|
+
offset += bytes.length;
|
|
37
|
+
return [bytes];
|
|
38
|
+
}))),
|
|
39
|
+
contentLength: length,
|
|
40
|
+
range
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
const put = Effect.fnUntraced(function* (context, request) {
|
|
44
|
+
const { fs, path } = context;
|
|
45
|
+
const headers = {
|
|
46
|
+
contentType: request.contentType,
|
|
47
|
+
contentEncoding: request.contentEncoding,
|
|
48
|
+
contentLanguage: request.contentLanguage,
|
|
49
|
+
contentDisposition: request.contentDisposition,
|
|
50
|
+
cacheControl: request.cacheControl,
|
|
51
|
+
customMetadata: request.customMetadata ? { ...request.customMetadata } : void 0
|
|
52
|
+
};
|
|
53
|
+
const limit = Math.min(context.maxObjectBytes, request.maxBytes ?? context.maxObjectBytes);
|
|
54
|
+
if (new TextEncoder().encode(request.key).length > 4096) return yield* storageError("put", "filesystem", {
|
|
55
|
+
_tag: "InvalidInput",
|
|
56
|
+
field: "key"
|
|
57
|
+
}, "not-started");
|
|
58
|
+
if (new TextEncoder().encode(JSON.stringify(headers)).length > 32768) return yield* storageError("put", "filesystem", {
|
|
59
|
+
_tag: "InvalidInput",
|
|
60
|
+
field: "metadata"
|
|
61
|
+
}, "not-started");
|
|
62
|
+
if (request.contentLength !== void 0 && request.contentLength > limit) return yield* storageError("put", "filesystem", {
|
|
63
|
+
_tag: "LimitExceeded",
|
|
64
|
+
limit
|
|
65
|
+
}, "not-started");
|
|
66
|
+
yield* context.checkDirectories;
|
|
67
|
+
const destination = yield* context.filename(request.key);
|
|
68
|
+
const temporary = path.join(context.staging, `upload-${yield* context.random.uuidV4()}.pending`);
|
|
69
|
+
let outcome = "not-started";
|
|
70
|
+
const map = (error) => mapIO("put", outcome)(error);
|
|
71
|
+
return yield* Effect.acquireUseRelease(Effect.succeed(temporary), () => Effect.gen(function* () {
|
|
72
|
+
const metadata = yield* Effect.scoped(Effect.gen(function* () {
|
|
73
|
+
const file = yield* fs.open(temporary, {
|
|
74
|
+
flag: "wx+",
|
|
75
|
+
mode: 384,
|
|
76
|
+
noFollow: true
|
|
77
|
+
}).pipe(Effect.mapError(map));
|
|
78
|
+
yield* file.seek(BigInt(headerBytes), "start").pipe(Effect.mapError(map));
|
|
79
|
+
const hash = context.hash.create();
|
|
80
|
+
let length = 0;
|
|
81
|
+
const source = Predicate.isUint8Array(request.body) ? Stream.succeed(request.body) : request.body;
|
|
82
|
+
yield* Stream.runForEach(source, (chunk) => Effect.gen(function* () {
|
|
83
|
+
if (!Predicate.isUint8Array(chunk)) return yield* storageError("put", "filesystem", {
|
|
84
|
+
_tag: "InvalidInput",
|
|
85
|
+
field: "body"
|
|
86
|
+
}, "not-started");
|
|
87
|
+
if (chunk.length > limit - length) return yield* storageError("put", "filesystem", {
|
|
88
|
+
_tag: "LimitExceeded",
|
|
89
|
+
limit
|
|
90
|
+
}, "not-started");
|
|
91
|
+
for (let offset = 0; offset < chunk.length; offset += 65536) {
|
|
92
|
+
const bytes = chunk.subarray(offset, offset + 65536);
|
|
93
|
+
hash.update(bytes);
|
|
94
|
+
yield* file.writeAll(bytes).pipe(Effect.uninterruptible, Effect.mapError(map));
|
|
95
|
+
}
|
|
96
|
+
length += chunk.length;
|
|
97
|
+
}));
|
|
98
|
+
if (request.contentLength !== void 0 && request.contentLength !== length) return yield* storageError("put", "filesystem", {
|
|
99
|
+
_tag: "LengthMismatch",
|
|
100
|
+
expected: request.contentLength,
|
|
101
|
+
actual: length
|
|
102
|
+
}, "not-started");
|
|
103
|
+
const saved = {
|
|
104
|
+
...headers,
|
|
105
|
+
ref: {
|
|
106
|
+
storeId: context.storeId,
|
|
107
|
+
key: request.key
|
|
108
|
+
},
|
|
109
|
+
size: length,
|
|
110
|
+
etag: `"${yield* context.random.uuidV4()}"`,
|
|
111
|
+
lastModified: yield* DateTime.now,
|
|
112
|
+
checksums: [hash.finish()]
|
|
113
|
+
};
|
|
114
|
+
const header = yield* encodeEnvelope(saved);
|
|
115
|
+
yield* file.seek(0n, "start").pipe(Effect.mapError(map));
|
|
116
|
+
yield* file.writeAll(header).pipe(Effect.uninterruptible, Effect.mapError(map));
|
|
117
|
+
yield* file.sync.pipe(Effect.uninterruptible, Effect.mapError(map));
|
|
118
|
+
return saved;
|
|
119
|
+
}));
|
|
120
|
+
yield* Effect.gen(function* () {
|
|
121
|
+
yield* context.checkDirectories;
|
|
122
|
+
yield* context.regularFile(destination).pipe(Effect.asVoid, Effect.catchReason("PlatformError", "NotFound", () => Effect.void), Effect.mapError((error) => error._tag === "PlatformError" ? map(error) : error));
|
|
123
|
+
outcome = "unknown";
|
|
124
|
+
if (request.condition?._tag === "CreateOnly") yield* fs.link(temporary, destination).pipe(Effect.catchReason("PlatformError", "AlreadyExists", () => storageError("put", "filesystem", { _tag: "PreconditionFailed" }, "rejected")), Effect.mapError((error) => error._tag === "PlatformError" ? map(error) : error));
|
|
125
|
+
else yield* fs.rename(temporary, destination).pipe(Effect.mapError(map));
|
|
126
|
+
yield* syncDirectory(fs, context.objects).pipe(Effect.mapError(map));
|
|
127
|
+
outcome = "succeeded";
|
|
128
|
+
}).pipe(Effect.uninterruptible);
|
|
129
|
+
return metadata;
|
|
130
|
+
}), () => fs.remove(temporary, { force: true }).pipe(Effect.andThen(syncDirectory(fs, context.staging)), Effect.mapError(map), Effect.orDie));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
export { get, head, put };
|
|
134
|
+
//# sourceMappingURL=operations.js.map
|