@slopware/sloppy-linux-x64 0.1.0-alpha.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/LICENSE +201 -0
- package/README.md +5 -0
- package/bin/sloppy +0 -0
- package/bin/sloppyc +0 -0
- package/docs/KNOWN_LIMITATIONS.md +16 -0
- package/docs/LICENSES.md +6 -0
- package/docs/NOTICE.md +8 -0
- package/examples/README.md +140 -0
- package/examples/auth-api/README.md +20 -0
- package/examples/auth-api/app.js +61 -0
- package/examples/auth-api/appsettings.json +7 -0
- package/examples/auth-api/sloppy.json +5 -0
- package/examples/cache-basic/README.md +9 -0
- package/examples/cache-basic/app.js +32 -0
- package/examples/cache-hybrid-postgres/README.md +10 -0
- package/examples/cache-hybrid-postgres/app.js +27 -0
- package/examples/cache-output-api/README.md +10 -0
- package/examples/cache-output-api/app.js +35 -0
- package/examples/codec-base64-hex/README.md +14 -0
- package/examples/codec-base64-hex/app.js +15 -0
- package/examples/codec-checksums/README.md +15 -0
- package/examples/codec-checksums/app.js +8 -0
- package/examples/codec-compression/README.md +13 -0
- package/examples/codec-compression/app.js +9 -0
- package/examples/codec-streaming-compression/README.md +19 -0
- package/examples/codec-streaming-compression/app.js +16 -0
- package/examples/codec-text-binary/README.md +16 -0
- package/examples/codec-text-binary/app.js +17 -0
- package/examples/compiler-hello/README.md +71 -0
- package/examples/compiler-hello/app.js +7 -0
- package/examples/compiler-hello/expected/app.js +8 -0
- package/examples/compiler-hello/expected/app.js.map +53 -0
- package/examples/compiler-hello/expected/app.plan.json +229 -0
- package/examples/compiler-hello/expected/routes.slrt +0 -0
- package/examples/config-basic/README.md +13 -0
- package/examples/config-basic/app.js +13 -0
- package/examples/config-basic/appsettings.json +7 -0
- package/examples/config-secrets-redaction/README.md +9 -0
- package/examples/config-secrets-redaction/app.js +9 -0
- package/examples/config-secrets-redaction/appsettings.json +5 -0
- package/examples/config-strict-mode/README.md +7 -0
- package/examples/config-strict-mode/app.js +10 -0
- package/examples/config-strict-mode/appsettings.json +7 -0
- package/examples/configured-api/README.md +38 -0
- package/examples/configured-api/app.js +12 -0
- package/examples/configured-api/appsettings.Development.json +5 -0
- package/examples/configured-api/appsettings.json +6 -0
- package/examples/configured-api/sloppy.json +5 -0
- package/examples/core-config-secrets/README.md +10 -0
- package/examples/core-config-secrets/app.js +15 -0
- package/examples/core-fs-time-codec/README.md +9 -0
- package/examples/core-fs-time-codec/app.js +8 -0
- package/examples/core-network-time-codec/README.md +11 -0
- package/examples/core-network-time-codec/app.js +20 -0
- package/examples/core-policy-audit/README.md +7 -0
- package/examples/core-policy-audit/app.js +22 -0
- package/examples/core-process-time-codec/README.md +8 -0
- package/examples/core-process-time-codec/app.js +28 -0
- package/examples/core-worker-time/README.md +8 -0
- package/examples/core-worker-time/app.js +17 -0
- package/examples/crypto-hash-hmac/README.md +17 -0
- package/examples/crypto-hash-hmac/app.js +29 -0
- package/examples/crypto-password/README.md +21 -0
- package/examples/crypto-password/app.js +12 -0
- package/examples/crypto-random-token/README.md +16 -0
- package/examples/crypto-random-token/app.js +12 -0
- package/examples/crypto-secret-constant-time/README.md +21 -0
- package/examples/crypto-secret-constant-time/app.js +15 -0
- package/examples/data-foundation/README.md +39 -0
- package/examples/data-foundation/app.js +63 -0
- package/examples/dependency-graph/README.md +19 -0
- package/examples/dependency-graph/fixtures/graph-helper/index.js +3 -0
- package/examples/dependency-graph/fixtures/graph-helper/package.json +6 -0
- package/examples/dependency-graph/package.json +7 -0
- package/examples/dependency-graph/public/message.txt +1 -0
- package/examples/dependency-graph/sloppy.json +9 -0
- package/examples/dependency-graph/src/main.ts +8 -0
- package/examples/dogfood/README.md +23 -0
- package/examples/dogfood/dogfood.json +136 -0
- package/examples/dynamic-module-include/README.md +20 -0
- package/examples/dynamic-module-include/public/readme.txt +1 -0
- package/examples/dynamic-module-include/sloppy.json +12 -0
- package/examples/dynamic-module-include/src/main.ts +6 -0
- package/examples/dynamic-module-include/src/plugins/alpha.js +3 -0
- package/examples/dynamic-module-include/src/plugins/beta.js +3 -0
- package/examples/ergonomics/README.md +42 -0
- package/examples/ergonomics/app.js +38 -0
- package/examples/framework-controller/README.md +12 -0
- package/examples/framework-controller/app.js +31 -0
- package/examples/framework-di-services/README.md +17 -0
- package/examples/framework-di-services/app.ts +40 -0
- package/examples/framework-explicit-binding/README.md +12 -0
- package/examples/framework-explicit-binding/app.ts +34 -0
- package/examples/framework-hello/README.md +16 -0
- package/examples/framework-hello/app.ts +16 -0
- package/examples/framework-postgres-crud/README.md +73 -0
- package/examples/framework-postgres-crud/app.ts +64 -0
- package/examples/framework-sqlite-crud/README.md +52 -0
- package/examples/framework-sqlite-crud/app.ts +90 -0
- package/examples/framework-sqlite-crud/appsettings.json +11 -0
- package/examples/framework-sqlserver-crud/README.md +73 -0
- package/examples/framework-sqlserver-crud/app.ts +64 -0
- package/examples/framework-validation-errors/README.md +12 -0
- package/examples/framework-validation-errors/app.ts +16 -0
- package/examples/fs-basic/README.md +24 -0
- package/examples/fs-basic/app.js +12 -0
- package/examples/fs-roots-policy/README.md +14 -0
- package/examples/fs-roots-policy/app.js +4 -0
- package/examples/fs-streams/README.md +18 -0
- package/examples/fs-streams/app.js +11 -0
- package/examples/fs-watch/README.md +19 -0
- package/examples/fs-watch/app.js +11 -0
- package/examples/hello/README.md +63 -0
- package/examples/hello/app.js +19 -0
- package/examples/hello-minimal/README.md +51 -0
- package/examples/hello-minimal/sloppy.json +5 -0
- package/examples/hello-minimal/src/main.ts +9 -0
- package/examples/http-client-basic/README.md +11 -0
- package/examples/http-client-basic/app.js +46 -0
- package/examples/http-client-generated/README.md +22 -0
- package/examples/http-client-generated/openapi.json +45 -0
- package/examples/http-client-resilience/README.md +4 -0
- package/examples/http-client-resilience/app.js +38 -0
- package/examples/http-client-runtime-loopback/README.md +24 -0
- package/examples/http-client-testhost/README.md +4 -0
- package/examples/http-client-testhost/app.js +27 -0
- package/examples/http-client-testhost-package-mock/README.md +26 -0
- package/examples/http-client-typed/README.md +5 -0
- package/examples/http-client-typed/app.js +33 -0
- package/examples/modules-api/README.md +30 -0
- package/examples/modules-api/app.js +9 -0
- package/examples/modules-api/modules/routes.js +16 -0
- package/examples/modules-api/sloppy.json +5 -0
- package/examples/modules-basic/README.md +32 -0
- package/examples/modules-basic/app.js +41 -0
- package/examples/net-deadline-cancel/README.md +13 -0
- package/examples/net-deadline-cancel/app.js +34 -0
- package/examples/net-local-ipc/README.md +12 -0
- package/examples/net-local-ipc/app.js +46 -0
- package/examples/net-policy-strict/README.md +12 -0
- package/examples/net-policy-strict/app.js +34 -0
- package/examples/net-tcp-client/README.md +10 -0
- package/examples/net-tcp-client/app.js +23 -0
- package/examples/net-tcp-echo/README.md +11 -0
- package/examples/net-tcp-echo/app.js +45 -0
- package/examples/net-tcp-server/README.md +10 -0
- package/examples/net-tcp-server/app.js +28 -0
- package/examples/node-compat-path-events/README.md +15 -0
- package/examples/node-compat-path-events/sloppy.json +6 -0
- package/examples/node-compat-path-events/src/main.ts +15 -0
- package/examples/ops-compiler/README.md +9 -0
- package/examples/ops-compiler/app.js +26 -0
- package/examples/ops-health-metrics-management/README.md +14 -0
- package/examples/ops-health-metrics-management/app.js +24 -0
- package/examples/orm-basic/README.md +17 -0
- package/examples/orm-basic/app.js +82 -0
- package/examples/orm-cursor-export/README.md +16 -0
- package/examples/orm-cursor-export/app.js +28 -0
- package/examples/orm-migrations/README.md +14 -0
- package/examples/orm-migrations/migrations/.gitkeep +1 -0
- package/examples/orm-migrations/sloppy.json +9 -0
- package/examples/orm-migrations/src/app.ts +34 -0
- package/examples/orm-relations-includes/README.md +10 -0
- package/examples/orm-relations-includes/app.js +47 -0
- package/examples/orm-testservices/README.md +37 -0
- package/examples/orm-testservices/test.mjs +32 -0
- package/examples/os-runtime-api/README.md +11 -0
- package/examples/os-runtime-api/app.js +44 -0
- package/examples/package-zod-like/README.md +28 -0
- package/examples/package-zod-like/fixtures/zod-like/index.js +48 -0
- package/examples/package-zod-like/fixtures/zod-like/package.json +12 -0
- package/examples/package-zod-like/package.json +7 -0
- package/examples/package-zod-like/sloppy.json +6 -0
- package/examples/package-zod-like/src/main.ts +16 -0
- package/examples/postgres-basic/README.md +31 -0
- package/examples/postgres-basic/app.js +50 -0
- package/examples/prealpha-control-plane/README.md +50 -0
- package/examples/prealpha-control-plane/appsettings.Development.json +11 -0
- package/examples/prealpha-control-plane/appsettings.json +15 -0
- package/examples/prealpha-control-plane/sloppy.json +5 -0
- package/examples/prealpha-control-plane/src/db/schema.js +7 -0
- package/examples/prealpha-control-plane/src/db/seed.js +6 -0
- package/examples/prealpha-control-plane/src/main.js +21 -0
- package/examples/prealpha-control-plane/src/routes/apps.js +34 -0
- package/examples/prealpha-control-plane/src/routes/builds.js +25 -0
- package/examples/prealpha-control-plane/src/routes/deployments.js +19 -0
- package/examples/prealpha-control-plane/src/routes/diagnostics.js +11 -0
- package/examples/prealpha-control-plane/src/routes/health.js +27 -0
- package/examples/prealpha-control-plane/src/routes/projects.js +38 -0
- package/examples/prealpha-control-plane/src/services/diagnosticsSink.js +11 -0
- package/examples/prealpha-control-plane/src/services/repositories.js +9 -0
- package/examples/prealpha-control-plane/src/validation/schemas.js +6 -0
- package/examples/program-fs-process/README.md +31 -0
- package/examples/program-fs-process/sloppy.json +9 -0
- package/examples/program-fs-process/src/main.ts +27 -0
- package/examples/program-hello/README.md +32 -0
- package/examples/program-hello/main.ts +8 -0
- package/examples/program-hello/message.ts +1 -0
- package/examples/program-hello/sloppy.json +5 -0
- package/examples/rate-limit-auth/README.md +3 -0
- package/examples/rate-limit-auth/app.js +14 -0
- package/examples/rate-limit-basic/README.md +3 -0
- package/examples/rate-limit-basic/app.js +13 -0
- package/examples/rate-limit-redis/README.md +5 -0
- package/examples/rate-limit-redis/app.js +20 -0
- package/examples/rate-limit-testhost/README.md +4 -0
- package/examples/rate-limit-testhost/app.js +13 -0
- package/examples/rate-limit-websocket/README.md +3 -0
- package/examples/rate-limit-websocket/app.js +16 -0
- package/examples/realtime-auth/README.md +8 -0
- package/examples/realtime-auth/app.js +25 -0
- package/examples/realtime-auth/test.mjs +43 -0
- package/examples/realtime-chat/README.md +8 -0
- package/examples/realtime-chat/app.js +32 -0
- package/examples/realtime-chat/test.mjs +52 -0
- package/examples/realtime-dashboard/README.md +20 -0
- package/examples/realtime-dashboard/app.js +37 -0
- package/examples/realtime-presence/README.md +8 -0
- package/examples/realtime-presence/app.js +32 -0
- package/examples/realtime-presence/test.mjs +50 -0
- package/examples/realtime-testhost/README.md +8 -0
- package/examples/realtime-testhost/test.mjs +31 -0
- package/examples/redis-basic/README.md +17 -0
- package/examples/redis-basic/app.js +39 -0
- package/examples/redis-cache/README.md +14 -0
- package/examples/redis-cache/app.js +36 -0
- package/examples/redis-locks/README.md +13 -0
- package/examples/redis-locks/app.js +49 -0
- package/examples/request-context/README.md +32 -0
- package/examples/request-context/app.js +15 -0
- package/examples/sqlite-basic/README.md +52 -0
- package/examples/sqlite-basic/app.js +56 -0
- package/examples/sqlserver-basic/README.md +36 -0
- package/examples/sqlserver-basic/app.js +59 -0
- package/examples/static-files-basic/README.md +11 -0
- package/examples/static-files-basic/app.js +12 -0
- package/examples/static-files-basic/public/app.js +1 -0
- package/examples/static-files-basic/public/site.css +3 -0
- package/examples/static-files-package/README.md +12 -0
- package/examples/static-files-package/app.js +10 -0
- package/examples/static-files-package/public/index.html +2 -0
- package/examples/static-files-precompressed/README.md +12 -0
- package/examples/static-files-precompressed/app.js +11 -0
- package/examples/static-files-precompressed/public/app.js +1 -0
- package/examples/static-files-precompressed/public/app.js.br +0 -0
- package/examples/static-files-precompressed/public/app.js.gz +0 -0
- package/examples/static-files-spa/README.md +12 -0
- package/examples/static-files-spa/app.js +16 -0
- package/examples/static-files-spa/dist/assets/app.js +1 -0
- package/examples/static-files-spa/dist/index.html +4 -0
- package/examples/static-files-testhost/README.md +8 -0
- package/examples/static-files-testhost/app.js +13 -0
- package/examples/static-files-testhost/public/app.js +1 -0
- package/examples/static-files-testhost/public/app.js.gz +0 -0
- package/examples/static-files-testhost/test.mjs +38 -0
- package/examples/testhost-basic/README.md +26 -0
- package/examples/testhost-db/README.md +31 -0
- package/examples/testservices-postgres/README.md +68 -0
- package/examples/testservices-redis/README.md +71 -0
- package/examples/testservices-sqlserver/README.md +75 -0
- package/examples/time-basic/README.md +18 -0
- package/examples/time-basic/app.js +12 -0
- package/examples/time-deadline-cancellation/README.md +11 -0
- package/examples/time-deadline-cancellation/app.js +27 -0
- package/examples/time-fake-clock/README.md +14 -0
- package/examples/time-fake-clock/app.js +25 -0
- package/examples/time-interval-schedule/README.md +13 -0
- package/examples/time-interval-schedule/app.js +60 -0
- package/examples/users-api-sqlite/README.md +74 -0
- package/examples/users-api-sqlite/app.js +11 -0
- package/examples/users-api-sqlite/appsettings.Development.json +11 -0
- package/examples/users-api-sqlite/appsettings.json +11 -0
- package/examples/users-api-sqlite/modules/users.js +40 -0
- package/examples/users-api-sqlite/sloppy.json +5 -0
- package/examples/validation-errors/README.md +36 -0
- package/examples/validation-errors/app.js +14 -0
- package/examples/validation-errors/invalid-user.http +6 -0
- package/examples/validation-errors/sloppy.json +5 -0
- package/examples/web-dynamic-routes/README.md +17 -0
- package/examples/web-dynamic-routes/app.ts +27 -0
- package/examples/webhooks-basic/README.md +11 -0
- package/examples/webhooks-basic/app.js +48 -0
- package/examples/websocket-auth/README.md +8 -0
- package/examples/websocket-auth/app.js +16 -0
- package/examples/websocket-echo/README.md +9 -0
- package/examples/websocket-echo/app.js +36 -0
- package/examples/websocket-json-schema/README.md +5 -0
- package/examples/websocket-json-schema/app.js +25 -0
- package/examples/websocket-testhost/README.md +11 -0
- package/examples/websocket-testhost/test.mjs +49 -0
- package/examples/workers-background-service/README.md +7 -0
- package/examples/workers-background-service/app.js +16 -0
- package/examples/workers-js-isolate/README.md +8 -0
- package/examples/workers-js-isolate/app.js +19 -0
- package/examples/workers-js-isolate/workers/parser.ts +11 -0
- package/examples/workers-shutdown/README.md +6 -0
- package/examples/workers-shutdown/app.js +26 -0
- package/examples/workers-workerpool/README.md +6 -0
- package/examples/workers-workerpool/app.js +23 -0
- package/examples/workers-workqueue/README.md +8 -0
- package/examples/workers-workqueue/app.js +24 -0
- package/manifest.json +59 -0
- package/package.json +34 -0
- package/stdlib/sloppy/README.md +177 -0
- package/stdlib/sloppy/app.js +2142 -0
- package/stdlib/sloppy/auth.js +1813 -0
- package/stdlib/sloppy/bootstrap.manifest.json +83 -0
- package/stdlib/sloppy/cache.js +1542 -0
- package/stdlib/sloppy/codec.js +1153 -0
- package/stdlib/sloppy/config.js +61 -0
- package/stdlib/sloppy/crypto.js +312 -0
- package/stdlib/sloppy/data.js +2945 -0
- package/stdlib/sloppy/ffi.js +185 -0
- package/stdlib/sloppy/fs.js +795 -0
- package/stdlib/sloppy/health.js +603 -0
- package/stdlib/sloppy/http.js +1595 -0
- package/stdlib/sloppy/index.js +59 -0
- package/stdlib/sloppy/internal/bytes.js +31 -0
- package/stdlib/sloppy/internal/capabilities.js +155 -0
- package/stdlib/sloppy/internal/config.js +640 -0
- package/stdlib/sloppy/internal/disposable.js +31 -0
- package/stdlib/sloppy/internal/headers.js +63 -0
- package/stdlib/sloppy/internal/intrinsics.js +2 -0
- package/stdlib/sloppy/internal/json.js +20 -0
- package/stdlib/sloppy/internal/logging.js +278 -0
- package/stdlib/sloppy/internal/modules.js +405 -0
- package/stdlib/sloppy/internal/redaction.js +87 -0
- package/stdlib/sloppy/internal/routes.js +2279 -0
- package/stdlib/sloppy/internal/runtime-classic.js +19837 -0
- package/stdlib/sloppy/internal/services.js +690 -0
- package/stdlib/sloppy/internal/shared.js +32 -0
- package/stdlib/sloppy/internal/testhost-diagnostics.js +88 -0
- package/stdlib/sloppy/internal/testhost-http-server.js +238 -0
- package/stdlib/sloppy/internal/testhost-http.js +118 -0
- package/stdlib/sloppy/internal/testhost-loopback.js +50 -0
- package/stdlib/sloppy/internal/testservices-docker.js +154 -0
- package/stdlib/sloppy/internal/validation.js +117 -0
- package/stdlib/sloppy/metrics.js +427 -0
- package/stdlib/sloppy/net.js +5208 -0
- package/stdlib/sloppy/node/assert/strict.js +39 -0
- package/stdlib/sloppy/node/assert.js +228 -0
- package/stdlib/sloppy/node/buffer.js +247 -0
- package/stdlib/sloppy/node/console.js +33 -0
- package/stdlib/sloppy/node/constants.js +9 -0
- package/stdlib/sloppy/node/crypto.js +89 -0
- package/stdlib/sloppy/node/diagnostics_channel.js +41 -0
- package/stdlib/sloppy/node/events.js +113 -0
- package/stdlib/sloppy/node/fs/promises.js +27 -0
- package/stdlib/sloppy/node/fs.js +280 -0
- package/stdlib/sloppy/node/http.js +11 -0
- package/stdlib/sloppy/node/https.js +11 -0
- package/stdlib/sloppy/node/module.js +40 -0
- package/stdlib/sloppy/node/os.js +22 -0
- package/stdlib/sloppy/node/path.js +78 -0
- package/stdlib/sloppy/node/perf_hooks.js +12 -0
- package/stdlib/sloppy/node/process.js +129 -0
- package/stdlib/sloppy/node/querystring.js +21 -0
- package/stdlib/sloppy/node/stream/promises.js +3 -0
- package/stdlib/sloppy/node/stream.js +132 -0
- package/stdlib/sloppy/node/string_decoder.js +23 -0
- package/stdlib/sloppy/node/timers.js +26 -0
- package/stdlib/sloppy/node/tty.js +18 -0
- package/stdlib/sloppy/node/url.js +17 -0
- package/stdlib/sloppy/node/util.js +95 -0
- package/stdlib/sloppy/node/zlib.js +72 -0
- package/stdlib/sloppy/orm.js +2188 -0
- package/stdlib/sloppy/os.js +580 -0
- package/stdlib/sloppy/problem-details.js +29 -0
- package/stdlib/sloppy/providers/sqlite.js +26 -0
- package/stdlib/sloppy/rate-limit.js +856 -0
- package/stdlib/sloppy/realtime.js +1508 -0
- package/stdlib/sloppy/redis.js +1272 -0
- package/stdlib/sloppy/request-id.js +184 -0
- package/stdlib/sloppy/request-logging.js +101 -0
- package/stdlib/sloppy/results.js +933 -0
- package/stdlib/sloppy/schema.js +546 -0
- package/stdlib/sloppy/testing.js +4081 -0
- package/stdlib/sloppy/testservices.js +1041 -0
- package/stdlib/sloppy/time.js +894 -0
- package/stdlib/sloppy/webhooks.js +1330 -0
- package/stdlib/sloppy/workers.js +986 -0
- package/templates/api/README.md +82 -0
- package/templates/api/appsettings.Development.json +14 -0
- package/templates/api/appsettings.json +13 -0
- package/templates/api/data/.gitkeep +1 -0
- package/templates/api/gitignore +4 -0
- package/templates/api/migrations/0001_create_users.sql +1 -0
- package/templates/api/package.json +16 -0
- package/templates/api/public/hello.txt +1 -0
- package/templates/api/sloppy.json +14 -0
- package/templates/api/src/config.ts +1 -0
- package/templates/api/src/db/migrate.ts +14 -0
- package/templates/api/src/db/schema.ts +4 -0
- package/templates/api/src/db/usersRepository.ts +23 -0
- package/templates/api/src/main.ts +18 -0
- package/templates/api/src/models/user.ts +7 -0
- package/templates/api/src/routes/health.ts +20 -0
- package/templates/api/src/routes/users.ts +40 -0
- package/templates/api/src/services/usersService.ts +21 -0
- package/templates/api/tsconfig.json +15 -0
- package/templates/cli/README.md +16 -0
- package/templates/cli/gitignore +2 -0
- package/templates/cli/package.json +13 -0
- package/templates/cli/sloppy.json +6 -0
- package/templates/cli/src/commands/echo.ts +9 -0
- package/templates/cli/src/commands/inspect.ts +20 -0
- package/templates/cli/src/main.ts +50 -0
- package/templates/cli/tsconfig.json +15 -0
- package/templates/minimal-api/README.md +14 -0
- package/templates/minimal-api/gitignore +3 -0
- package/templates/minimal-api/package.json +14 -0
- package/templates/minimal-api/sloppy.json +5 -0
- package/templates/minimal-api/src/main.ts +9 -0
- package/templates/minimal-api/tsconfig.json +15 -0
- package/templates/node-compat/README.md +40 -0
- package/templates/node-compat/gitignore +2 -0
- package/templates/node-compat/package.json +11 -0
- package/templates/node-compat/sloppy.json +6 -0
- package/templates/node-compat/src/main.ts +40 -0
- package/templates/package-api/README.md +44 -0
- package/templates/package-api/fixtures/validator-lite/index.js +7 -0
- package/templates/package-api/fixtures/validator-lite/package.json +6 -0
- package/templates/package-api/gitignore +3 -0
- package/templates/package-api/package.json +17 -0
- package/templates/package-api/sloppy.json +5 -0
- package/templates/package-api/src/main.ts +10 -0
- package/templates/package-api/src/routes/health.ts +5 -0
- package/templates/package-api/src/routes/users.ts +12 -0
- package/templates/package-api/tsconfig.json +15 -0
- package/templates/program/README.md +12 -0
- package/templates/program/gitignore +1 -0
- package/templates/program/package.json +10 -0
- package/templates/program/sloppy.json +6 -0
- package/templates/program/src/main.ts +9 -0
|
@@ -0,0 +1,894 @@
|
|
|
1
|
+
class SloppyTimeError extends Error {
|
|
2
|
+
constructor(name, message, options = undefined) {
|
|
3
|
+
super(message, options);
|
|
4
|
+
this.name = name;
|
|
5
|
+
if (options && Object.prototype.hasOwnProperty.call(options, "reason")) {
|
|
6
|
+
this.reason = options.reason;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class TimeoutError extends SloppyTimeError {
|
|
12
|
+
constructor(message = "Sloppy time operation exceeded its deadline.", options) {
|
|
13
|
+
super("TimeoutError", message, options);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class CancelledError extends SloppyTimeError {
|
|
18
|
+
constructor(message = "Sloppy time operation was cancelled.", options) {
|
|
19
|
+
super("CancelledError", message, options);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class InvalidDeadlineError extends SloppyTimeError {
|
|
24
|
+
constructor(message = "Sloppy deadline is invalid.", options) {
|
|
25
|
+
super("InvalidDeadlineError", message, options);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class TimerDisposedError extends SloppyTimeError {
|
|
30
|
+
constructor(message = "Sloppy timer resource was disposed.", options) {
|
|
31
|
+
super("TimerDisposedError", message, options);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const MAX_DELAY_MS = 0xffffffff;
|
|
36
|
+
const NATIVE_TIMER_DISPOSED_MESSAGE = "Sloppy timer was disposed before completion";
|
|
37
|
+
const INTERVAL_UNITS_MS = Object.freeze({
|
|
38
|
+
ms: 1,
|
|
39
|
+
s: 1000,
|
|
40
|
+
m: 60 * 1000,
|
|
41
|
+
h: 60 * 60 * 1000,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function unavailable(operation) {
|
|
45
|
+
throw new Error(`SLOPPY_E_UNAVAILABLE_RUNTIME_FEATURE: runtime feature stdlib.time is inactive or unavailable
|
|
46
|
+
|
|
47
|
+
Feature:
|
|
48
|
+
stdlib.time
|
|
49
|
+
|
|
50
|
+
Operation:
|
|
51
|
+
${operation}
|
|
52
|
+
|
|
53
|
+
Reason:
|
|
54
|
+
Runtime scheduling requires the native time bridge to be registered in the active V8 lane.`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function nativeTime(operation) {
|
|
58
|
+
const bridge = globalThis.__sloppy?.time;
|
|
59
|
+
if (bridge === undefined || bridge === null) {
|
|
60
|
+
unavailable(operation);
|
|
61
|
+
}
|
|
62
|
+
return bridge;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function validateDelayMs(ms, operation) {
|
|
66
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0 || ms > MAX_DELAY_MS) {
|
|
67
|
+
throw new InvalidDeadlineError(
|
|
68
|
+
`${operation} requires a finite non-negative millisecond delay no greater than ${MAX_DELAY_MS}.`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return Math.ceil(ms);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function monotonicNowMs() {
|
|
75
|
+
const bridge = globalThis.__sloppy?.time;
|
|
76
|
+
return bridge && typeof bridge.monotonicMs === "function" ? bridge.monotonicMs() : Date.now();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function timeoutError(reason = undefined) {
|
|
80
|
+
return reason instanceof TimeoutError
|
|
81
|
+
? reason
|
|
82
|
+
: new TimeoutError("Sloppy time operation exceeded its deadline.", { reason });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function cancelledError(reason = undefined) {
|
|
86
|
+
return reason instanceof CancelledError
|
|
87
|
+
? reason
|
|
88
|
+
: new CancelledError("Sloppy time operation was cancelled.", { reason });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function normalizeNativeTimerError(error) {
|
|
92
|
+
if (error instanceof TimerDisposedError) {
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
if (error instanceof Error && error.message === NATIVE_TIMER_DISPOSED_MESSAGE) {
|
|
96
|
+
throw new TimerDisposedError(error.message, { reason: error });
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function timerDisposedError(reason = undefined) {
|
|
102
|
+
return reason instanceof TimerDisposedError
|
|
103
|
+
? reason
|
|
104
|
+
: new TimerDisposedError("Sloppy timer resource was disposed.", { reason });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
class CancellationSignal {
|
|
108
|
+
constructor() {
|
|
109
|
+
this.aborted = false;
|
|
110
|
+
this.reason = undefined;
|
|
111
|
+
this._listeners = new Set();
|
|
112
|
+
Object.seal(this);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
throwIfCancelled() {
|
|
116
|
+
if (this.aborted) {
|
|
117
|
+
throw cancelledError(this.reason);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
addEventListener(type, listener) {
|
|
122
|
+
if (type !== "abort" || typeof listener !== "function") {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this._listeners.add(listener);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
removeEventListener(type, listener) {
|
|
129
|
+
if (type === "abort") {
|
|
130
|
+
this._listeners.delete(listener);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
_subscribe(listener) {
|
|
135
|
+
if (typeof listener !== "function") {
|
|
136
|
+
return () => {};
|
|
137
|
+
}
|
|
138
|
+
if (this.aborted) {
|
|
139
|
+
listener(this.reason);
|
|
140
|
+
return () => {};
|
|
141
|
+
}
|
|
142
|
+
this._listeners.add(listener);
|
|
143
|
+
return () => {
|
|
144
|
+
this._listeners.delete(listener);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_cancel(reason) {
|
|
149
|
+
if (this.aborted) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
this.aborted = true;
|
|
153
|
+
this.reason = reason;
|
|
154
|
+
const listeners = Array.from(this._listeners);
|
|
155
|
+
this._listeners.clear();
|
|
156
|
+
const errors = [];
|
|
157
|
+
for (const listener of listeners) {
|
|
158
|
+
try {
|
|
159
|
+
listener(reason);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
errors.push(error);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (errors.length > 0) {
|
|
165
|
+
throw new AggregateError(errors, "one or more abort listeners threw");
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function isCancellationSignal(value) {
|
|
172
|
+
return (
|
|
173
|
+
value instanceof CancellationSignal ||
|
|
174
|
+
(value !== null &&
|
|
175
|
+
typeof value === "object" &&
|
|
176
|
+
typeof value.aborted === "boolean" &&
|
|
177
|
+
("reason" in value || typeof value.addEventListener === "function"))
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function subscribeCancellation(signal, listener) {
|
|
182
|
+
if (!isCancellationSignal(signal)) {
|
|
183
|
+
return () => {};
|
|
184
|
+
}
|
|
185
|
+
if (signal.aborted) {
|
|
186
|
+
listener(signal.reason);
|
|
187
|
+
return () => {};
|
|
188
|
+
}
|
|
189
|
+
if (typeof signal._subscribe === "function") {
|
|
190
|
+
return signal._subscribe(listener);
|
|
191
|
+
}
|
|
192
|
+
if (typeof signal.addEventListener === "function") {
|
|
193
|
+
const wrapped = () => listener(signal.reason);
|
|
194
|
+
signal.addEventListener("abort", wrapped);
|
|
195
|
+
return () => signal.removeEventListener?.("abort", wrapped);
|
|
196
|
+
}
|
|
197
|
+
return () => {};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
class DeadlineValue {
|
|
201
|
+
constructor(expiresAtMonotonicMs, kind) {
|
|
202
|
+
this.expiresAtMonotonicMs = expiresAtMonotonicMs;
|
|
203
|
+
this.kind = kind;
|
|
204
|
+
Object.freeze(this);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
remainingMs() {
|
|
208
|
+
if (this.expiresAtMonotonicMs === Infinity) {
|
|
209
|
+
return Infinity;
|
|
210
|
+
}
|
|
211
|
+
return Math.max(0, this.expiresAtMonotonicMs - monotonicNowMs());
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
get expired() {
|
|
215
|
+
return this.remainingMs() <= 0;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const Deadline = Object.freeze({
|
|
220
|
+
after(ms) {
|
|
221
|
+
return new DeadlineValue(monotonicNowMs() + validateDelayMs(ms, "Deadline.after"), "after");
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
at(dateOrUnixMs) {
|
|
225
|
+
const unixMs =
|
|
226
|
+
dateOrUnixMs instanceof Date ? dateOrUnixMs.getTime() : Number(dateOrUnixMs);
|
|
227
|
+
if (!Number.isFinite(unixMs)) {
|
|
228
|
+
throw new InvalidDeadlineError("Deadline.at requires a finite Date or Unix millisecond value.");
|
|
229
|
+
}
|
|
230
|
+
return Deadline.after(Math.max(0, unixMs - Date.now()));
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
never() {
|
|
234
|
+
return new DeadlineValue(Infinity, "never");
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
function deadlineDelayMs(deadline) {
|
|
239
|
+
if (deadline === undefined || deadline === null) {
|
|
240
|
+
return Infinity;
|
|
241
|
+
}
|
|
242
|
+
if (typeof deadline.remainingMs !== "function") {
|
|
243
|
+
throw new InvalidDeadlineError("Time operation deadline must come from Deadline.after, Deadline.at, or Deadline.never.");
|
|
244
|
+
}
|
|
245
|
+
return deadline.remainingMs();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function registerCancellationTimer(controller, delayMs, reasonFactory) {
|
|
249
|
+
const timer = setTimeout(() => {
|
|
250
|
+
if (!controller._disposed) {
|
|
251
|
+
try {
|
|
252
|
+
controller.cancel(reasonFactory());
|
|
253
|
+
} catch {
|
|
254
|
+
// Timer-triggered cancellation should not crash the host when listeners throw.
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}, Math.ceil(delayMs));
|
|
258
|
+
controller._cleanups.push(() => clearTimeout(timer));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
class CancellationController {
|
|
262
|
+
constructor(options = undefined) {
|
|
263
|
+
this.signal = new CancellationSignal();
|
|
264
|
+
this._disposed = false;
|
|
265
|
+
this._cleanups = [];
|
|
266
|
+
Object.seal(this);
|
|
267
|
+
|
|
268
|
+
const linked = options?.signal ?? options?.signals;
|
|
269
|
+
const signals = Array.isArray(linked) ? linked : linked === undefined ? [] : [linked];
|
|
270
|
+
for (const signal of signals) {
|
|
271
|
+
this._cleanups.push(subscribeCancellation(signal, (reason) => this.cancel(reason)));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (options?.timeoutMs !== undefined) {
|
|
275
|
+
const timeoutMs = validateDelayMs(options.timeoutMs, "CancellationController timeout");
|
|
276
|
+
registerCancellationTimer(this, timeoutMs, () => timeoutError());
|
|
277
|
+
}
|
|
278
|
+
if (options?.deadline !== undefined) {
|
|
279
|
+
const remaining = deadlineDelayMs(options.deadline);
|
|
280
|
+
if (remaining <= 0) {
|
|
281
|
+
this.cancel(timeoutError(options.deadline));
|
|
282
|
+
} else if (remaining !== Infinity) {
|
|
283
|
+
registerCancellationTimer(this, remaining, () => timeoutError(options.deadline));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
cancel(reason = "cancelled") {
|
|
289
|
+
if (this._disposed) {
|
|
290
|
+
throw new TimerDisposedError("CancellationController was disposed.");
|
|
291
|
+
}
|
|
292
|
+
return this.signal._cancel(reason);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
dispose() {
|
|
296
|
+
if (this._disposed) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
this._disposed = true;
|
|
300
|
+
for (const cleanup of this._cleanups.splice(0)) {
|
|
301
|
+
cleanup();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
static linked(...signals) {
|
|
306
|
+
return new CancellationController({ signals });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
static timeout(timeoutMs, options = undefined) {
|
|
310
|
+
return new CancellationController({ ...options, timeoutMs });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function raceCancellation(promise, signal) {
|
|
315
|
+
if (!isCancellationSignal(signal)) {
|
|
316
|
+
return promise;
|
|
317
|
+
}
|
|
318
|
+
if (signal.aborted) {
|
|
319
|
+
return Promise.reject(cancelledError(signal.reason));
|
|
320
|
+
}
|
|
321
|
+
return new Promise((resolve, reject) => {
|
|
322
|
+
const cleanup = subscribeCancellation(signal, (reason) => {
|
|
323
|
+
cleanup();
|
|
324
|
+
reject(cancelledError(reason));
|
|
325
|
+
});
|
|
326
|
+
promise.then(
|
|
327
|
+
(value) => {
|
|
328
|
+
cleanup();
|
|
329
|
+
resolve(value);
|
|
330
|
+
},
|
|
331
|
+
(error) => {
|
|
332
|
+
cleanup();
|
|
333
|
+
reject(error);
|
|
334
|
+
},
|
|
335
|
+
);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function cancelAndDisposeController(controller, reason) {
|
|
340
|
+
try {
|
|
341
|
+
controller.cancel(reason);
|
|
342
|
+
} catch (_) {
|
|
343
|
+
// Cleanup paths must not be derailed by user abort listeners.
|
|
344
|
+
}
|
|
345
|
+
controller.dispose();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function parseIntervalMs(value, operation) {
|
|
349
|
+
if (typeof value === "number") {
|
|
350
|
+
const ms = validateDelayMs(value, operation);
|
|
351
|
+
if (ms <= 0) {
|
|
352
|
+
throw new InvalidDeadlineError(`${operation} requires an interval greater than 0.`);
|
|
353
|
+
}
|
|
354
|
+
return ms;
|
|
355
|
+
}
|
|
356
|
+
if (typeof value === "string") {
|
|
357
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)$/.exec(value.trim());
|
|
358
|
+
if (match === null) {
|
|
359
|
+
throw new InvalidDeadlineError(
|
|
360
|
+
`${operation} requires a millisecond number or interval string such as "500ms", "5s", "5m", or "1h".`,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
return parseIntervalMs(Number(match[1]) * INTERVAL_UNITS_MS[match[2]], operation);
|
|
364
|
+
}
|
|
365
|
+
throw new InvalidDeadlineError(`${operation} requires a millisecond number or interval string.`);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function validateMaxTicks(maxTicks, operation) {
|
|
369
|
+
if (maxTicks === undefined) {
|
|
370
|
+
return Infinity;
|
|
371
|
+
}
|
|
372
|
+
if (!Number.isInteger(maxTicks) || maxTicks < 0) {
|
|
373
|
+
throw new InvalidDeadlineError(`${operation} maxTicks must be a non-negative integer.`);
|
|
374
|
+
}
|
|
375
|
+
return maxTicks;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function clockNow(clock) {
|
|
379
|
+
return clock && typeof clock.now === "function" ? clock.now() : new Date();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function clockMonotonicNowMs(clock) {
|
|
383
|
+
return clock && typeof clock.monotonicNowMs === "function"
|
|
384
|
+
? clock.monotonicNowMs()
|
|
385
|
+
: monotonicNowMs();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function validateClockDeadlineOptions(options, operation) {
|
|
389
|
+
if (options?.clock !== undefined && options.clock !== null && options?.deadline !== undefined) {
|
|
390
|
+
throw new InvalidDeadlineError(
|
|
391
|
+
`${operation} does not support deadline with an injected clock; use a duration option with that clock.`,
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function delayWithDeadline(ms, options = undefined, operation = "Time.delay") {
|
|
397
|
+
const delayMs = validateDelayMs(ms, operation);
|
|
398
|
+
if (isCancellationSignal(options?.signal) && options.signal.aborted) {
|
|
399
|
+
return Promise.reject(cancelledError(options.signal.reason));
|
|
400
|
+
}
|
|
401
|
+
validateClockDeadlineOptions(options, operation);
|
|
402
|
+
const remaining = deadlineDelayMs(options?.deadline);
|
|
403
|
+
if (remaining <= 0) {
|
|
404
|
+
return Promise.reject(timeoutError(options?.deadline));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const actualDelay = Math.min(delayMs, remaining);
|
|
408
|
+
if (options?.clock !== undefined && options.clock !== null) {
|
|
409
|
+
if (typeof options.clock.delay !== "function") {
|
|
410
|
+
return Promise.reject(
|
|
411
|
+
new InvalidDeadlineError("Time clock providers must expose delay(ms, options)."),
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
return options.clock.delay(actualDelay, { signal: options?.signal }).then(() => {
|
|
415
|
+
if (actualDelay < delayMs) {
|
|
416
|
+
throw timeoutError(options?.deadline);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const promise = nativeTime("Time.delay")
|
|
422
|
+
.delay(actualDelay)
|
|
423
|
+
.then(() => {
|
|
424
|
+
if (actualDelay < delayMs) {
|
|
425
|
+
throw timeoutError(options?.deadline);
|
|
426
|
+
}
|
|
427
|
+
})
|
|
428
|
+
.catch(normalizeNativeTimerError);
|
|
429
|
+
return raceCancellation(promise, options?.signal);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function systemDelay(ms, options = undefined) {
|
|
433
|
+
return delayWithDeadline(ms, { ...options, clock: undefined });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
class TimeInterval {
|
|
437
|
+
constructor(ms, options = undefined) {
|
|
438
|
+
this._intervalMs = parseIntervalMs(ms, "Time.interval");
|
|
439
|
+
this._clock = options?.clock;
|
|
440
|
+
this._signal = options?.signal;
|
|
441
|
+
this._immediate = options?.immediate === true;
|
|
442
|
+
this._maxTicks = validateMaxTicks(options?.maxTicks, "Time.interval");
|
|
443
|
+
this._ticks = 0;
|
|
444
|
+
this._stopped = false;
|
|
445
|
+
this._nextInFlight = null;
|
|
446
|
+
this._cleanup = subscribeCancellation(this._signal, () => {
|
|
447
|
+
this._stopped = true;
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
[Symbol.asyncIterator]() {
|
|
452
|
+
return this;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
next() {
|
|
456
|
+
if (this._nextInFlight !== null) {
|
|
457
|
+
return Promise.reject(new Error("Time.interval does not support overlapping next() calls."));
|
|
458
|
+
}
|
|
459
|
+
this._nextInFlight = this._nextImpl();
|
|
460
|
+
return this._nextInFlight.finally(() => {
|
|
461
|
+
this._nextInFlight = null;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async _nextImpl() {
|
|
466
|
+
if (this._stopped || this._ticks >= this._maxTicks) {
|
|
467
|
+
this._cleanup();
|
|
468
|
+
return { done: true, value: undefined };
|
|
469
|
+
}
|
|
470
|
+
if (!(this._immediate && this._ticks === 0)) {
|
|
471
|
+
try {
|
|
472
|
+
await Time.delay(this._intervalMs, {
|
|
473
|
+
clock: this._clock,
|
|
474
|
+
signal: this._signal,
|
|
475
|
+
});
|
|
476
|
+
} catch (error) {
|
|
477
|
+
if (error instanceof CancelledError) {
|
|
478
|
+
this._stopped = true;
|
|
479
|
+
this._cleanup();
|
|
480
|
+
return { done: true, value: undefined };
|
|
481
|
+
}
|
|
482
|
+
throw error;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (this._stopped || this._ticks >= this._maxTicks) {
|
|
486
|
+
this._cleanup();
|
|
487
|
+
return { done: true, value: undefined };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
this._ticks += 1;
|
|
491
|
+
if (this._ticks >= this._maxTicks) {
|
|
492
|
+
this._cleanup();
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
done: false,
|
|
496
|
+
value: Object.freeze({
|
|
497
|
+
index: this._ticks,
|
|
498
|
+
at: clockNow(this._clock),
|
|
499
|
+
scheduledAt: clockNow(this._clock),
|
|
500
|
+
}),
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async return() {
|
|
505
|
+
this.stop();
|
|
506
|
+
return { done: true, value: undefined };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
stop() {
|
|
510
|
+
this._stopped = true;
|
|
511
|
+
this._cleanup();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
class ScheduledJob {
|
|
516
|
+
constructor(interval, handler, options = undefined) {
|
|
517
|
+
if (typeof handler !== "function") {
|
|
518
|
+
throw new TypeError("Time.every requires an async job handler.");
|
|
519
|
+
}
|
|
520
|
+
const missedRunPolicy = options?.missedRunPolicy ?? "skip";
|
|
521
|
+
if (missedRunPolicy !== "skip") {
|
|
522
|
+
throw new InvalidDeadlineError('Time.every only supports missedRunPolicy: "skip".');
|
|
523
|
+
}
|
|
524
|
+
this._intervalMs = parseIntervalMs(interval, "Time.every");
|
|
525
|
+
this._handler = handler;
|
|
526
|
+
this._clock = options?.clock;
|
|
527
|
+
this._controller = new CancellationController({ signal: options?.signal });
|
|
528
|
+
this._noOverlap = options?.noOverlap !== false;
|
|
529
|
+
this._maxRuns = validateMaxTicks(options?.maxRuns, "Time.every");
|
|
530
|
+
this._paused = false;
|
|
531
|
+
this._stopped = false;
|
|
532
|
+
this._running = false;
|
|
533
|
+
this._runCount = 0;
|
|
534
|
+
this._skippedRuns = 0;
|
|
535
|
+
this._lastError = undefined;
|
|
536
|
+
this._nextRunMs =
|
|
537
|
+
clockMonotonicNowMs(this._clock) + (options?.immediate === true ? 0 : this._intervalMs);
|
|
538
|
+
this._loopPromise = this._runLoop();
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
get running() {
|
|
542
|
+
return this._running;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
get stopped() {
|
|
546
|
+
return this._stopped;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
get skippedRuns() {
|
|
550
|
+
return this._skippedRuns;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
get lastError() {
|
|
554
|
+
return this._lastError;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
get nextRun() {
|
|
558
|
+
if (this._stopped) {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
const remaining = Math.max(0, this._nextRunMs - clockMonotonicNowMs(this._clock));
|
|
562
|
+
return new Date(clockNow(this._clock).getTime() + remaining);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
pause() {
|
|
566
|
+
if (this._stopped) {
|
|
567
|
+
throw timerDisposedError();
|
|
568
|
+
}
|
|
569
|
+
this._paused = true;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
resume() {
|
|
573
|
+
if (this._stopped) {
|
|
574
|
+
throw timerDisposedError();
|
|
575
|
+
}
|
|
576
|
+
this._paused = false;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
stop(reason = "scheduled job stopped") {
|
|
580
|
+
if (this._stopped) {
|
|
581
|
+
return this._loopPromise;
|
|
582
|
+
}
|
|
583
|
+
this._finishStopped(reason, true);
|
|
584
|
+
return this._loopPromise;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
async _runLoop() {
|
|
588
|
+
while (!this._stopped) {
|
|
589
|
+
if (this._runCount >= this._maxRuns) {
|
|
590
|
+
this._finishStopped("scheduled job completed");
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
const waitMs = Math.max(0, this._nextRunMs - clockMonotonicNowMs(this._clock));
|
|
594
|
+
try {
|
|
595
|
+
await Time.delay(waitMs, {
|
|
596
|
+
clock: this._clock,
|
|
597
|
+
signal: this._controller.signal,
|
|
598
|
+
});
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (error instanceof CancelledError || error instanceof TimerDisposedError) {
|
|
601
|
+
this._finishStopped(error);
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
this._lastError = error;
|
|
605
|
+
this._finishStopped(error);
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (this._stopped) {
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
if (this._paused) {
|
|
613
|
+
this._nextRunMs += this._intervalMs;
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
if (this._running && this._noOverlap) {
|
|
617
|
+
this._skippedRuns += 1;
|
|
618
|
+
this._nextRunMs += this._intervalMs;
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
this._startRun();
|
|
623
|
+
this._nextRunMs += this._intervalMs;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
_startRun() {
|
|
628
|
+
this._running = true;
|
|
629
|
+
this._runCount += 1;
|
|
630
|
+
const context = Object.freeze({
|
|
631
|
+
signal: this._controller.signal,
|
|
632
|
+
scheduledAt: this.nextRun,
|
|
633
|
+
startedAt: clockNow(this._clock),
|
|
634
|
+
run: this._runCount,
|
|
635
|
+
skippedRuns: this._skippedRuns,
|
|
636
|
+
});
|
|
637
|
+
Promise.resolve()
|
|
638
|
+
.then(() => this._handler(context))
|
|
639
|
+
.catch((error) => {
|
|
640
|
+
this._lastError = error;
|
|
641
|
+
})
|
|
642
|
+
.finally(() => {
|
|
643
|
+
this._running = false;
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
_finishStopped(reason, cancel = false) {
|
|
648
|
+
if (this._stopped) {
|
|
649
|
+
this._controller.dispose();
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
this._stopped = true;
|
|
653
|
+
if (cancel) {
|
|
654
|
+
cancelAndDisposeController(this._controller, reason);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
this._controller.dispose();
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
class FakeClock {
|
|
662
|
+
constructor(options = undefined) {
|
|
663
|
+
const wallMs =
|
|
664
|
+
options?.now instanceof Date
|
|
665
|
+
? options.now.getTime()
|
|
666
|
+
: options?.now === undefined
|
|
667
|
+
? 0
|
|
668
|
+
: Number(options.now);
|
|
669
|
+
if (!Number.isFinite(wallMs)) {
|
|
670
|
+
throw new InvalidDeadlineError("Time.fakeClock now must be a finite Date or Unix millisecond value.");
|
|
671
|
+
}
|
|
672
|
+
this.kind = "fake";
|
|
673
|
+
this._wallMs = wallMs;
|
|
674
|
+
this._nowMs = 0;
|
|
675
|
+
this._disposed = false;
|
|
676
|
+
this._timers = [];
|
|
677
|
+
this._timerSeq = 0;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
now() {
|
|
681
|
+
this._throwIfDisposed();
|
|
682
|
+
return new Date(this._wallMs);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
monotonicNowMs() {
|
|
686
|
+
this._throwIfDisposed();
|
|
687
|
+
return this._nowMs;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
delay(ms, options = undefined) {
|
|
691
|
+
const delayMs = validateDelayMs(ms, "FakeClock.delay");
|
|
692
|
+
if (this._disposed) {
|
|
693
|
+
return Promise.reject(timerDisposedError());
|
|
694
|
+
}
|
|
695
|
+
if (isCancellationSignal(options?.signal) && options.signal.aborted) {
|
|
696
|
+
return Promise.reject(cancelledError(options.signal.reason));
|
|
697
|
+
}
|
|
698
|
+
const remaining = deadlineDelayMs(options?.deadline);
|
|
699
|
+
if (remaining <= 0) {
|
|
700
|
+
return Promise.reject(timeoutError(options?.deadline));
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const actualDelay = Math.min(delayMs, remaining);
|
|
704
|
+
if (actualDelay === 0) {
|
|
705
|
+
return actualDelay < delayMs ? Promise.reject(timeoutError(options?.deadline)) : Promise.resolve();
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return new Promise((resolve, reject) => {
|
|
709
|
+
const timer = {
|
|
710
|
+
dueMs: this._nowMs + actualDelay,
|
|
711
|
+
seq: this._timerSeq += 1,
|
|
712
|
+
reject,
|
|
713
|
+
resolve: () => {
|
|
714
|
+
cleanup();
|
|
715
|
+
if (actualDelay < delayMs) {
|
|
716
|
+
reject(timeoutError(options?.deadline));
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
resolve();
|
|
720
|
+
},
|
|
721
|
+
};
|
|
722
|
+
const cleanup = subscribeCancellation(options?.signal, (reason) => {
|
|
723
|
+
this._removeTimer(timer);
|
|
724
|
+
reject(cancelledError(reason));
|
|
725
|
+
});
|
|
726
|
+
timer.cleanup = cleanup;
|
|
727
|
+
this._timers.push(timer);
|
|
728
|
+
this._flushDueTimers();
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
set(dateOrUnixMs) {
|
|
733
|
+
this._throwIfDisposed();
|
|
734
|
+
const nextWallMs =
|
|
735
|
+
dateOrUnixMs instanceof Date ? dateOrUnixMs.getTime() : Number(dateOrUnixMs);
|
|
736
|
+
if (!Number.isFinite(nextWallMs)) {
|
|
737
|
+
throw new InvalidDeadlineError("FakeClock.set requires a finite Date or Unix millisecond value.");
|
|
738
|
+
}
|
|
739
|
+
const delta = nextWallMs - this._wallMs;
|
|
740
|
+
if (delta > 0) {
|
|
741
|
+
this.advanceBy(delta);
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
this._wallMs = nextWallMs;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
advanceBy(ms) {
|
|
748
|
+
this._throwIfDisposed();
|
|
749
|
+
const delta = validateDelayMs(ms, "FakeClock.advanceBy");
|
|
750
|
+
this._nowMs += delta;
|
|
751
|
+
this._wallMs += delta;
|
|
752
|
+
this._flushDueTimers();
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
dispose() {
|
|
756
|
+
if (this._disposed) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
this._disposed = true;
|
|
760
|
+
const timers = this._timers.splice(0);
|
|
761
|
+
for (const timer of timers) {
|
|
762
|
+
timer.cleanup?.();
|
|
763
|
+
timer.reject(timerDisposedError());
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
_throwIfDisposed() {
|
|
768
|
+
if (this._disposed) {
|
|
769
|
+
throw timerDisposedError();
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
_removeTimer(timer) {
|
|
774
|
+
const index = this._timers.indexOf(timer);
|
|
775
|
+
if (index >= 0) {
|
|
776
|
+
this._timers.splice(index, 1);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
_flushDueTimers() {
|
|
781
|
+
if (this._disposed) {
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const due = [];
|
|
785
|
+
this._timers = this._timers.filter((timer) => {
|
|
786
|
+
if (timer.dueMs <= this._nowMs) {
|
|
787
|
+
due.push(timer);
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
return true;
|
|
791
|
+
});
|
|
792
|
+
due.sort((left, right) => left.dueMs - right.dueMs || left.seq - right.seq);
|
|
793
|
+
for (const timer of due) {
|
|
794
|
+
timer.resolve();
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const Time = Object.freeze({
|
|
800
|
+
delay(ms, options = undefined) {
|
|
801
|
+
return delayWithDeadline(ms, options);
|
|
802
|
+
},
|
|
803
|
+
|
|
804
|
+
timeout(operationOrPromise, options = undefined) {
|
|
805
|
+
validateClockDeadlineOptions(options, "Time.timeout");
|
|
806
|
+
const afterMs =
|
|
807
|
+
options?.afterMs !== undefined ? validateDelayMs(options.afterMs, "Time.timeout") : Infinity;
|
|
808
|
+
const deadlineMs = deadlineDelayMs(options?.deadline);
|
|
809
|
+
const timeoutMs = Math.min(afterMs, deadlineMs);
|
|
810
|
+
if (timeoutMs === Infinity) {
|
|
811
|
+
throw new InvalidDeadlineError("Time.timeout requires afterMs or deadline.");
|
|
812
|
+
}
|
|
813
|
+
if (isCancellationSignal(options?.signal) && options.signal.aborted) {
|
|
814
|
+
return Promise.reject(cancelledError(options.signal.reason));
|
|
815
|
+
}
|
|
816
|
+
if (timeoutMs <= 0) {
|
|
817
|
+
return Promise.reject(timeoutError(options?.deadline));
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
if (typeof operationOrPromise === "function") {
|
|
821
|
+
const controller = new CancellationController({ signal: options?.signal });
|
|
822
|
+
const timeoutController = new CancellationController({ signal: options?.signal });
|
|
823
|
+
const timeoutPromise = Time.delay(timeoutMs, {
|
|
824
|
+
clock: options?.clock,
|
|
825
|
+
signal: timeoutController.signal,
|
|
826
|
+
}).then(() => {
|
|
827
|
+
const error = timeoutError(options?.deadline);
|
|
828
|
+
try {
|
|
829
|
+
controller.cancel(error);
|
|
830
|
+
} catch (_) {
|
|
831
|
+
// Timeout remains authoritative even when user abort listeners throw.
|
|
832
|
+
}
|
|
833
|
+
throw error;
|
|
834
|
+
});
|
|
835
|
+
const operationPromise = Promise.resolve().then(() => operationOrPromise(controller.signal));
|
|
836
|
+
const race = [operationPromise, timeoutPromise];
|
|
837
|
+
if (isCancellationSignal(options?.signal)) {
|
|
838
|
+
race.push(raceCancellation(new Promise(() => {}), options.signal));
|
|
839
|
+
}
|
|
840
|
+
return Promise.race(race).finally(() => {
|
|
841
|
+
cancelAndDisposeController(timeoutController, "timeout race settled");
|
|
842
|
+
controller.dispose();
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const timeoutController = new CancellationController({ signal: options?.signal });
|
|
847
|
+
return Promise.race([
|
|
848
|
+
raceCancellation(Promise.resolve(operationOrPromise), options?.signal),
|
|
849
|
+
Time.delay(timeoutMs, {
|
|
850
|
+
clock: options?.clock,
|
|
851
|
+
signal: timeoutController.signal,
|
|
852
|
+
}).then(() => {
|
|
853
|
+
throw timeoutError(options?.deadline);
|
|
854
|
+
}),
|
|
855
|
+
]).finally(() => {
|
|
856
|
+
cancelAndDisposeController(timeoutController, "timeout race settled");
|
|
857
|
+
});
|
|
858
|
+
},
|
|
859
|
+
|
|
860
|
+
interval(ms, options = undefined) {
|
|
861
|
+
return new TimeInterval(ms, options);
|
|
862
|
+
},
|
|
863
|
+
|
|
864
|
+
every(interval, handler, options = undefined) {
|
|
865
|
+
return new ScheduledJob(interval, handler, options);
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
yield(options = undefined) {
|
|
869
|
+
return delayWithDeadline(0, options);
|
|
870
|
+
},
|
|
871
|
+
|
|
872
|
+
systemClock() {
|
|
873
|
+
return Object.freeze({
|
|
874
|
+
kind: "system",
|
|
875
|
+
now: () => new Date(),
|
|
876
|
+
monotonicNowMs,
|
|
877
|
+
delay: systemDelay,
|
|
878
|
+
});
|
|
879
|
+
},
|
|
880
|
+
|
|
881
|
+
fakeClock(options = undefined) {
|
|
882
|
+
return new FakeClock(options);
|
|
883
|
+
},
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
export {
|
|
887
|
+
CancelledError,
|
|
888
|
+
CancellationController,
|
|
889
|
+
Deadline,
|
|
890
|
+
InvalidDeadlineError,
|
|
891
|
+
Time,
|
|
892
|
+
TimeoutError,
|
|
893
|
+
TimerDisposedError,
|
|
894
|
+
};
|