diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index f819f89..f441716 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -40,7 +40,7 @@ jobs: id: cache-cargo uses: actions/cache@v4 with: - key: python-sdk-compatible-1 + key: python-sdk-compatible-2 path: | ~/.cargo/bin/ - name: Install wasm-tools and wac @@ -49,7 +49,7 @@ jobs: - name: Install viceroy if: steps.cache-cargo.outputs.cache-hit != 'true' # When you switch tags, update the cache key in the cache-cargo step. - run: cargo install --git https://github.com/fastly/Viceroy.git --tag erik/python-sdk-compatible-1 viceroy + run: cargo install --git https://github.com/fastly/Viceroy.git --tag erik/python-sdk-compatible-2 viceroy - name: Install dependencies run: uv sync --extra dev --extra test - name: Check formatting diff --git a/fastly_compute/wsgi.py b/fastly_compute/wsgi.py index 1273bfa..32d5b69 100644 --- a/fastly_compute/wsgi.py +++ b/fastly_compute/wsgi.py @@ -23,7 +23,7 @@ ) from wit_world.imports.http_req import send from wit_world.imports.http_resp import send_downstream -from wit_world.imports.types import Err, Error_OptionalNone +from wit_world.imports.types import Err, Error_CannotRead def serve_wsgi_request( @@ -201,7 +201,7 @@ def handle(self, request: Any, body: Any) -> None: # we're really interested in, per Python's idiom. Rather than # carting around a Result type that's Union[Ok[T], Err[E]], we # should probably return T xor raise E. - if isinstance(exc.value, Error_OptionalNone): + if isinstance(exc.value, Error_CannotRead): # There were no more requests within the timeout. break else: diff --git a/wit/deps/fastly/compute.wit b/wit/deps/fastly/compute.wit index 068584d..94358a8 100644 --- a/wit/deps/fastly/compute.wit +++ b/wit/deps/fastly/compute.wit @@ -22,11 +22,21 @@ interface types { generic-error, /// Invalid argument. invalid-argument, - /// Invalid handle. + /// Auxiliary error value. /// - /// Returned when a handle is not valid, for example when no dictionary exists with the given - /// name. - bad-handle, + /// For `cache.get-body` and `cache.replace-get-body`, it means the cache implementation was + /// busy and not ready to retrieve the body data. + /// + /// For cache APIs that attempt to write to or update the body of a cache transaction, it means + /// that an error occurred while attempting the write or update. + /// + /// For other cache APIs, it indicates that the underlying cache entry or cache replace entry + /// is no longer available. + /// + /// For writing to a streaming HTTP body, indicates that the body has already been closed. + /// + /// For a dictionary lookup, indicates that the dictionary was not found. + auxiliary-error, /// Buffer length error. /// /// Returned when a buffer is the wrong size. @@ -51,11 +61,10 @@ interface types { /// /// This can be returned when a stream ended unexpectedly. http-incomplete, - /// A “none” error. + /// Cannot read. /// - /// This status code is used to indicate when an optional value did not exist, as opposed to - /// an empty value. - optional-none, + /// An error occurred while attempting to read the body of a cache transaction. + cannot-read, /// Message head too large. http-head-too-large, /// Invalid HTTP status. @@ -315,9 +324,8 @@ interface log { /// Writes a data to the given endpoint. /// - /// Each call to `write` produces a single log event. On success, the number of bytes written - /// is returned. - write: func(msg: list) -> result; + /// Each call to `write` with a non-empty message produces a single log event. + write: func(msg: list); } } @@ -355,10 +363,6 @@ interface http-downstream { pending: pending-request, ) -> result, error>; - next-request-abandon: func( - pending: pending-request, - ) -> result<_, error>; - /// Returns the client request's header names exactly as they were originally received. /// /// This includes both the original header name characters' cases, as well as the original order @@ -874,19 +878,6 @@ interface http-req { error: error, } - /// Configuration for inspecting a `request` using Security. - record inspect-options { - corp: option, - workspace: option, - override-client-ip: option, - - /// Additional options may be added in the future via this resource type. - extra: option>, - } - - /// Extensibility for `inspect-options` - resource extra-inspect-options {} - /// Waits until the request is completed, and then returns the resulting /// response and body. await-response: func( @@ -907,7 +898,7 @@ interface http-req { /// /// [Fastly Next-Gen WAF]: https://docs.fastly.com/en/ngwaf/ interface security { - use http-req.{request, body, inspect-options, error}; + use http-req.{request, body, ip-address, error}; /// Inspects request HTTP traffic using the [NGWAF] lookaside service. /// @@ -920,6 +911,19 @@ interface security { options: inspect-options, max-len: u64 ) -> result; + + /// Configuration for inspecting a `request` using Security. + record inspect-options { + corp: option, + workspace: option, + override-client-ip: option, + + /// Additional options may be added in the future via this resource type. + extra: option>, + } + + /// Extensibility for `inspect-options` + resource extra-inspect-options {} } /// HTTP responses. @@ -2039,79 +2043,56 @@ interface cache { use async-io.{pollable as pending-entry}; /// A replace operation. - type replace-entry = entry; + resource replace-entry { + /// The entrypoint to the replace API. + /// + /// This operation always participates in request collapsing and may return stale objects. + replace: static func( + key: list, + options: replace-options, + ) -> result; - /// The entrypoint to the replace API. - /// - /// This operation always participates in request collapsing and may return stale objects. - replace: func( - key: list, - options: replace-options, - ) -> result; + /// Gets the age of the existing object during replace, returning + /// `ok(none)` if there was no object. + get-age-ns: func() -> result, error>; - /// Replace an object in the cache with the given metadata - /// - /// The returned handle is to a streaming body that is used for writing the object into - /// the cache. - replace-insert: func( - handle: borrow, - options: write-options, - ) -> result; + /// Gets a range of the existing object body, returning `ok(none)` if there + /// was no existing object. + /// + /// The returned `body` must be closed before calling this function + /// again on the same `replace-entry`. + get-body: func( + options: get-body-options, + ) -> result, error>; - /// Gets the age of the existing object during replace, returning - /// `ok(none)` if there was no object. - replace-get-age-ns: func( - handle: borrow, - ) -> result, error>; - - /// Gets a range of the existing object body, returning `ok(none)` if there - /// was no existing object. - /// - /// The returned `body` must be closed before calling this function - /// again on the same `replace-entry`. - replace-get-body: func( - handle: borrow, - options: get-body-options, - ) -> result, error>; - - /// Gets the number of cache hits for the existing object during replace, - /// returning `ok(none)` if there was no object. - replace-get-hits: func( - handle: borrow, - ) -> result, error>; - - /// Gets the content length of the existing object during replace, - /// returning `ok(none)` if there was no object, or no content - /// length was provided. - replace-get-length: func( - handle: borrow, - ) -> result, error>; - - /// Gets the configured max age of the existing object during replace, - /// returning `ok(none)` if there was no object. - replace-get-max-age-ns: func( - handle: borrow, - ) -> result, error>; - - /// Gets the configured stale-while-revalidate period of the existing - /// object during replace, returning `ok(none)` if there was no - /// object. - replace-get-stale-while-revalidate-ns: func( - handle: borrow, - ) -> result, error>; - - /// Gets the lookup state of the existing object during replace, returning - /// `ok(none)` if there was no object. - replace-get-state: func( - handle: borrow, - ) -> result, error>; - - /// Gets the user metadata of the existing object during replace, returning - /// `ok(none)` if there was no object. - replace-get-user-metadata: func( - handle: borrow, - max-len: u64, - ) -> result>, error>; + /// Gets the number of cache hits for the existing object during replace, + /// returning `ok(none)` if there was no object. + get-hits: func() -> result, error>; + + /// Gets the content length of the existing object during replace, + /// returning `ok(none)` if there was no object, or no content + /// length was provided. + get-length: func() -> result, error>; + + /// Gets the configured max age of the existing object during replace, + /// returning `ok(none)` if there was no object. + get-max-age-ns: func() -> result, error>; + + /// Gets the configured stale-while-revalidate period of the existing + /// object during replace, returning `ok(none)` if there was no + /// object. + get-stale-while-revalidate-ns: func() -> result, error>; + + /// Gets the lookup state of the existing object during replace, returning + /// `ok(none)` if there was no object. + get-state: func() -> result, error>; + + /// Gets the user metadata of the existing object during replace, returning + /// `ok(none)` if there was no object. + get-user-metadata: func( + max-len: u64, + ) -> result>, error>; + } type object-length = u64; type duration-ns = u64; @@ -2222,10 +2203,24 @@ interface cache { /// If the cache handle state includes the `must-insert-or-update` (and hence no insert or /// update has been performed), closing the handle cancels any request collapsing, potentially /// choosing a new waiter to perform the insertion/update. - /// - /// This may be passed either an `entry` or a `replace-entry`. close-entry: func(handle: entry) -> result<_, error>; + /// Replace an object in the cache with the given metadata + /// + /// The returned handle is to a streaming body that is used for writing the object into + /// the cache. + replace-insert: func( + handle: replace-entry, + options: write-options, + ) -> result; + + /// Closes an ongoing replace interaction with the cache. + /// + /// If the replace handle state includes the `must-insert-or-update` (and hence no insert or + /// update has been performed), closing the handle cancels any request collapsing, potentially + /// choosing a new waiter to perform the insertion/update. + close-replace-entry: func(handle: replace-entry) -> result<_, error>; + /// Options for cache replace operations record replace-options { /// a full request handle, but used only for its headers @@ -2837,6 +2832,8 @@ world service-imports { import wasi:io/streams@0.2.6; import wasi:io/poll@0.2.6; import wasi:random/random@0.2.6; + import wasi:random/insecure@0.2.6; + import wasi:random/insecure-seed@0.2.6; import wasi:cli/environment@0.2.6; import wasi:cli/exit@0.2.6; import wasi:cli/stdout@0.2.6;