@stackframe/stack-shared 2.8.8 → 2.8.11
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 +14 -0
- package/dist/config/format.d.cts +39 -0
- package/dist/config/format.d.ts +14 -13
- package/dist/config/format.js +147 -206
- package/dist/config/format.js.map +1 -0
- package/dist/config/schema.d.cts +729 -0
- package/dist/config/schema.d.ts +59 -51
- package/dist/config/schema.js +232 -172
- package/dist/config/schema.js.map +1 -0
- package/dist/crud.d.cts +102 -0
- package/dist/crud.d.ts +15 -13
- package/dist/crud.js +83 -128
- package/dist/crud.js.map +1 -0
- package/dist/esm/config/format.js +135 -0
- package/dist/esm/config/format.js.map +1 -0
- package/dist/esm/config/schema.js +201 -0
- package/dist/esm/config/schema.js.map +1 -0
- package/dist/esm/crud.js +60 -0
- package/dist/esm/crud.js.map +1 -0
- package/dist/esm/global.d.js +1 -0
- package/dist/esm/global.d.js.map +1 -0
- package/dist/esm/helpers/password.js +17 -0
- package/dist/esm/helpers/password.js.map +1 -0
- package/dist/esm/helpers/production-mode.js +50 -0
- package/dist/esm/helpers/production-mode.js.map +1 -0
- package/dist/esm/hooks/use-async-callback.js +38 -0
- package/dist/esm/hooks/use-async-callback.js.map +1 -0
- package/dist/esm/hooks/use-async-external-store.js +23 -0
- package/dist/esm/hooks/use-async-external-store.js.map +1 -0
- package/dist/esm/hooks/use-hash.js +17 -0
- package/dist/esm/hooks/use-hash.js.map +1 -0
- package/dist/esm/hooks/use-strict-memo.js +61 -0
- package/dist/esm/hooks/use-strict-memo.js.map +1 -0
- package/dist/esm/index.js +22 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interface/adminInterface.js +244 -0
- package/dist/esm/interface/adminInterface.js.map +1 -0
- package/dist/esm/interface/clientInterface.js +2041 -0
- package/dist/esm/interface/clientInterface.js.map +1 -0
- package/dist/esm/interface/crud/contact-channels.js +77 -0
- package/dist/esm/interface/crud/contact-channels.js.map +1 -0
- package/dist/esm/interface/crud/current-user.js +65 -0
- package/dist/esm/interface/crud/current-user.js.map +1 -0
- package/dist/esm/interface/crud/email-templates.js +52 -0
- package/dist/esm/interface/crud/email-templates.js.map +1 -0
- package/dist/esm/interface/crud/emails.js +20 -0
- package/dist/esm/interface/crud/emails.js.map +1 -0
- package/dist/esm/interface/crud/internal-api-keys.js +69 -0
- package/dist/esm/interface/crud/internal-api-keys.js.map +1 -0
- package/dist/esm/interface/crud/oauth.js +24 -0
- package/dist/esm/interface/crud/oauth.js.map +1 -0
- package/dist/esm/interface/crud/project-api-keys.js +93 -0
- package/dist/esm/interface/crud/project-api-keys.js.map +1 -0
- package/dist/esm/interface/crud/project-permissions.js +113 -0
- package/dist/esm/interface/crud/project-permissions.js.map +1 -0
- package/dist/esm/interface/crud/projects.js +180 -0
- package/dist/esm/interface/crud/projects.js.map +1 -0
- package/dist/esm/interface/crud/sessions.js +62 -0
- package/dist/esm/interface/crud/sessions.js.map +1 -0
- package/dist/esm/interface/crud/svix-token.js +22 -0
- package/dist/esm/interface/crud/svix-token.js.map +1 -0
- package/dist/esm/interface/crud/team-invitation-details.js +23 -0
- package/dist/esm/interface/crud/team-invitation-details.js.map +1 -0
- package/dist/esm/interface/crud/team-invitation.js +36 -0
- package/dist/esm/interface/crud/team-invitation.js.map +1 -0
- package/dist/esm/interface/crud/team-member-profiles.js +62 -0
- package/dist/esm/interface/crud/team-member-profiles.js.map +1 -0
- package/dist/esm/interface/crud/team-memberships.js +60 -0
- package/dist/esm/interface/crud/team-memberships.js.map +1 -0
- package/dist/esm/interface/crud/team-permissions.js +114 -0
- package/dist/esm/interface/crud/team-permissions.js.map +1 -0
- package/dist/esm/interface/crud/teams.js +143 -0
- package/dist/esm/interface/crud/teams.js.map +1 -0
- package/dist/esm/interface/crud/users.js +139 -0
- package/dist/esm/interface/crud/users.js.map +1 -0
- package/dist/esm/interface/serverInterface.js +485 -0
- package/dist/esm/interface/serverInterface.js.map +1 -0
- package/dist/esm/interface/webhooks.js +21 -0
- package/dist/esm/interface/webhooks.js.map +1 -0
- package/dist/esm/known-errors.js +1238 -0
- package/dist/esm/known-errors.js.map +1 -0
- package/dist/esm/schema-fields.js +484 -0
- package/dist/esm/schema-fields.js.map +1 -0
- package/dist/esm/sessions.js +168 -0
- package/dist/esm/sessions.js.map +1 -0
- package/dist/esm/utils/api-keys.js +79 -0
- package/dist/esm/utils/api-keys.js.map +1 -0
- package/dist/esm/utils/arrays.js +78 -0
- package/dist/esm/utils/arrays.js.map +1 -0
- package/dist/esm/utils/base64.js +18 -0
- package/dist/esm/utils/base64.js.map +1 -0
- package/dist/esm/utils/booleans.js +12 -0
- package/dist/esm/utils/booleans.js.map +1 -0
- package/dist/esm/utils/browser-compat.js +21 -0
- package/dist/esm/utils/browser-compat.js.map +1 -0
- package/dist/esm/utils/bytes.js +160 -0
- package/dist/esm/utils/bytes.js.map +1 -0
- package/dist/esm/utils/caches.js +167 -0
- package/dist/esm/utils/caches.js.map +1 -0
- package/dist/esm/utils/compile-time.js +11 -0
- package/dist/esm/utils/compile-time.js.map +1 -0
- package/dist/esm/utils/crypto.js +25 -0
- package/dist/esm/utils/crypto.js.map +1 -0
- package/dist/esm/utils/dates.js +64 -0
- package/dist/esm/utils/dates.js.map +1 -0
- package/dist/esm/utils/dom.js +11 -0
- package/dist/esm/utils/dom.js.map +1 -0
- package/dist/esm/utils/env.js +58 -0
- package/dist/esm/utils/env.js.map +1 -0
- package/dist/esm/utils/errors.js +174 -0
- package/dist/esm/utils/errors.js.map +1 -0
- package/dist/esm/utils/fs.js +37 -0
- package/dist/esm/utils/fs.js.map +1 -0
- package/dist/esm/utils/functions.js +12 -0
- package/dist/esm/utils/functions.js.map +1 -0
- package/dist/esm/utils/geo.js +15 -0
- package/dist/esm/utils/geo.js.map +1 -0
- package/dist/esm/utils/globals.js +18 -0
- package/dist/esm/utils/globals.js.map +1 -0
- package/dist/esm/utils/hashes.js +55 -0
- package/dist/esm/utils/hashes.js.map +1 -0
- package/dist/esm/utils/html.js +13 -0
- package/dist/esm/utils/html.js.map +1 -0
- package/dist/esm/utils/http.js +60 -0
- package/dist/esm/utils/http.js.map +1 -0
- package/dist/esm/utils/ips.js +15 -0
- package/dist/esm/utils/ips.js.map +1 -0
- package/dist/esm/utils/json.js +31 -0
- package/dist/esm/utils/json.js.map +1 -0
- package/dist/esm/utils/jwt.js +87 -0
- package/dist/esm/utils/jwt.js.map +1 -0
- package/dist/esm/utils/locks.js +57 -0
- package/dist/esm/utils/locks.js.map +1 -0
- package/dist/esm/utils/maps.js +181 -0
- package/dist/esm/utils/maps.js.map +1 -0
- package/dist/esm/utils/math.js +8 -0
- package/dist/esm/utils/math.js.map +1 -0
- package/dist/esm/utils/node-http.js +42 -0
- package/dist/esm/utils/node-http.js.map +1 -0
- package/dist/esm/utils/numbers.js +32 -0
- package/dist/esm/utils/numbers.js.map +1 -0
- package/dist/esm/utils/oauth.js +10 -0
- package/dist/esm/utils/oauth.js.map +1 -0
- package/dist/esm/utils/objects.js +177 -0
- package/dist/esm/utils/objects.js.map +1 -0
- package/dist/esm/utils/passkey.js +1 -0
- package/dist/esm/utils/passkey.js.map +1 -0
- package/dist/esm/utils/promises.js +233 -0
- package/dist/esm/utils/promises.js.map +1 -0
- package/dist/esm/utils/proxies.js +128 -0
- package/dist/esm/utils/proxies.js.map +1 -0
- package/dist/esm/utils/react.js +78 -0
- package/dist/esm/utils/react.js.map +1 -0
- package/dist/esm/utils/results.js +141 -0
- package/dist/esm/utils/results.js.map +1 -0
- package/dist/esm/utils/sentry.js +20 -0
- package/dist/esm/utils/sentry.js.map +1 -0
- package/dist/esm/utils/stores.js +195 -0
- package/dist/esm/utils/stores.js.map +1 -0
- package/dist/esm/utils/strings.js +295 -0
- package/dist/esm/utils/strings.js.map +1 -0
- package/dist/esm/utils/strings.nicify.test.js +222 -0
- package/dist/esm/utils/strings.nicify.test.js.map +1 -0
- package/dist/esm/utils/types.js +1 -0
- package/dist/esm/utils/types.js.map +1 -0
- package/dist/esm/utils/unicode.js +11 -0
- package/dist/esm/utils/unicode.js.map +1 -0
- package/dist/esm/utils/urls.js +53 -0
- package/dist/esm/utils/urls.js.map +1 -0
- package/dist/esm/utils/uuids.js +16 -0
- package/dist/esm/utils/uuids.js.map +1 -0
- package/dist/global.d.d.cts +1 -0
- package/dist/global.d.d.ts +1 -0
- package/dist/global.d.js +2 -0
- package/dist/global.d.js.map +1 -0
- package/dist/helpers/password.d.cts +11 -0
- package/dist/helpers/password.d.ts +11 -2
- package/dist/helpers/password.js +41 -11
- package/dist/helpers/password.js.map +1 -0
- package/dist/helpers/production-mode.d.cts +12 -0
- package/dist/helpers/production-mode.d.ts +9 -3
- package/dist/helpers/production-mode.js +72 -45
- package/dist/helpers/production-mode.js.map +1 -0
- package/dist/hooks/use-async-callback.d.cts +6 -0
- package/dist/hooks/use-async-callback.d.ts +6 -3
- package/dist/hooks/use-async-callback.js +72 -30
- package/dist/hooks/use-async-callback.js.map +1 -0
- package/dist/hooks/use-async-external-store.d.cts +7 -0
- package/dist/hooks/use-async-external-store.d.ts +5 -2
- package/dist/hooks/use-async-external-store.js +47 -19
- package/dist/hooks/use-async-external-store.js.map +1 -0
- package/dist/hooks/use-hash.d.cts +3 -0
- package/dist/hooks/use-hash.d.ts +3 -1
- package/dist/hooks/use-hash.js +41 -8
- package/dist/hooks/use-hash.js.map +1 -0
- package/dist/hooks/use-strict-memo.d.cts +8 -0
- package/dist/hooks/use-strict-memo.d.ts +3 -1
- package/dist/hooks/use-strict-memo.js +78 -131
- package/dist/hooks/use-strict-memo.js.map +1 -0
- package/dist/index.d.cts +30 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +42 -4
- package/dist/index.js.map +1 -0
- package/dist/interface/adminInterface.d.cts +94 -0
- package/dist/interface/adminInterface.d.ts +38 -15
- package/dist/interface/adminInterface.js +269 -174
- package/dist/interface/adminInterface.js.map +1 -0
- package/dist/interface/clientInterface.d.cts +260 -0
- package/dist/interface/clientInterface.d.ts +25 -18
- package/dist/interface/clientInterface.js +2054 -995
- package/dist/interface/clientInterface.js.map +1 -0
- package/dist/interface/crud/contact-channels.d.cts +180 -0
- package/dist/interface/crud/contact-channels.d.ts +30 -25
- package/dist/interface/crud/contact-channels.js +101 -59
- package/dist/interface/crud/contact-channels.js.map +1 -0
- package/dist/interface/crud/current-user.d.cts +205 -0
- package/dist/interface/crud/current-user.d.ts +17 -12
- package/dist/interface/crud/current-user.js +86 -56
- package/dist/interface/crud/current-user.js.map +1 -0
- package/dist/interface/crud/email-templates.d.cts +84 -0
- package/dist/interface/crud/email-templates.d.ts +24 -19
- package/dist/interface/crud/email-templates.js +77 -37
- package/dist/interface/crud/email-templates.js.map +1 -0
- package/dist/interface/crud/emails.d.cts +69 -0
- package/dist/interface/crud/emails.d.ts +12 -7
- package/dist/interface/crud/emails.js +54 -12
- package/dist/interface/crud/emails.js.map +1 -0
- package/dist/interface/crud/internal-api-keys.d.cts +139 -0
- package/dist/interface/crud/internal-api-keys.d.ts +22 -17
- package/dist/interface/crud/internal-api-keys.js +92 -54
- package/dist/interface/crud/internal-api-keys.js.map +1 -0
- package/dist/interface/crud/oauth.d.cts +34 -0
- package/dist/interface/crud/oauth.d.ts +16 -11
- package/dist/interface/crud/oauth.js +48 -14
- package/dist/interface/crud/oauth.js.map +1 -0
- package/dist/interface/crud/project-api-keys.d.cts +196 -0
- package/dist/interface/crud/project-api-keys.d.ts +20 -12
- package/dist/interface/crud/project-api-keys.js +121 -74
- package/dist/interface/crud/project-api-keys.js.map +1 -0
- package/dist/interface/crud/project-permissions.d.cts +160 -0
- package/dist/interface/crud/project-permissions.d.ts +38 -33
- package/dist/interface/crud/project-permissions.js +148 -90
- package/dist/interface/crud/project-permissions.js.map +1 -0
- package/dist/interface/crud/projects.d.cts +627 -0
- package/dist/interface/crud/projects.d.ts +43 -51
- package/dist/interface/crud/projects.js +210 -156
- package/dist/interface/crud/projects.js.map +1 -0
- package/dist/interface/crud/sessions.d.cts +149 -0
- package/dist/interface/crud/sessions.d.ts +21 -16
- package/dist/interface/crud/sessions.js +86 -50
- package/dist/interface/crud/sessions.js.map +1 -0
- package/dist/interface/crud/svix-token.d.cts +26 -0
- package/dist/interface/crud/svix-token.d.ts +14 -9
- package/dist/interface/crud/svix-token.js +46 -12
- package/dist/interface/crud/svix-token.js.map +1 -0
- package/dist/interface/crud/team-invitation-details.d.cts +30 -0
- package/dist/interface/crud/team-invitation-details.d.ts +12 -7
- package/dist/interface/crud/team-invitation-details.js +57 -15
- package/dist/interface/crud/team-invitation-details.js.map +1 -0
- package/dist/interface/crud/team-invitation.d.cts +49 -0
- package/dist/interface/crud/team-invitation.d.ts +13 -8
- package/dist/interface/crud/team-invitation.js +69 -27
- package/dist/interface/crud/team-invitation.js.map +1 -0
- package/dist/interface/crud/team-member-profiles.d.cts +229 -0
- package/dist/interface/crud/team-member-profiles.d.ts +20 -15
- package/dist/interface/crud/team-member-profiles.js +95 -49
- package/dist/interface/crud/team-member-profiles.js.map +1 -0
- package/dist/interface/crud/team-memberships.d.cts +74 -0
- package/dist/interface/crud/team-memberships.d.ts +22 -17
- package/dist/interface/crud/team-memberships.js +85 -45
- package/dist/interface/crud/team-memberships.js.map +1 -0
- package/dist/interface/crud/team-permissions.d.cts +168 -0
- package/dist/interface/crud/team-permissions.d.ts +38 -33
- package/dist/interface/crud/team-permissions.js +149 -91
- package/dist/interface/crud/team-permissions.js.map +1 -0
- package/dist/interface/crud/teams.d.cts +298 -0
- package/dist/interface/crud/teams.d.ts +45 -40
- package/dist/interface/crud/teams.js +177 -119
- package/dist/interface/crud/teams.js.map +1 -0
- package/dist/interface/crud/users.d.cts +469 -0
- package/dist/interface/crud/users.d.ts +31 -26
- package/dist/interface/crud/users.js +172 -118
- package/dist/interface/crud/users.js.map +1 -0
- package/dist/interface/serverInterface.d.cts +128 -0
- package/dist/interface/serverInterface.d.ts +29 -17
- package/dist/interface/serverInterface.js +506 -339
- package/dist/interface/serverInterface.js.map +1 -0
- package/dist/interface/webhooks.d.cts +292 -0
- package/dist/interface/webhooks.d.ts +6 -3
- package/dist/interface/webhooks.js +45 -15
- package/dist/interface/webhooks.js.map +1 -0
- package/dist/known-errors.d.cts +447 -0
- package/dist/known-errors.d.ts +15 -9
- package/dist/known-errors.js +1104 -562
- package/dist/known-errors.js.map +1 -0
- package/dist/schema-fields.d.cts +163 -0
- package/dist/schema-fields.d.ts +116 -114
- package/dist/schema-fields.js +593 -427
- package/dist/schema-fields.js.map +1 -0
- package/dist/sessions.d.cts +109 -0
- package/dist/sessions.d.ts +6 -3
- package/dist/sessions.js +201 -172
- package/dist/sessions.js.map +1 -0
- package/dist/utils/api-keys.d.cts +24 -0
- package/dist/utils/api-keys.d.ts +5 -4
- package/dist/utils/api-keys.js +106 -66
- package/dist/utils/api-keys.js.map +1 -0
- package/dist/utils/arrays.d.cts +18 -0
- package/dist/utils/arrays.d.ts +15 -13
- package/dist/utils/arrays.js +101 -168
- package/dist/utils/arrays.js.map +1 -0
- package/dist/utils/base64.d.cts +4 -0
- package/dist/utils/base64.d.ts +4 -2
- package/dist/utils/base64.js +41 -20
- package/dist/utils/base64.js.map +1 -0
- package/dist/utils/booleans.d.cts +6 -0
- package/dist/utils/booleans.d.ts +6 -4
- package/dist/utils/booleans.js +35 -27
- package/dist/utils/booleans.js.map +1 -0
- package/dist/utils/browser-compat.d.cts +8 -0
- package/dist/utils/browser-compat.d.ts +3 -1
- package/dist/utils/browser-compat.js +45 -16
- package/dist/utils/browser-compat.js.map +1 -0
- package/dist/utils/bytes.d.cts +15 -0
- package/dist/utils/bytes.d.ts +15 -13
- package/dist/utils/bytes.js +182 -270
- package/dist/utils/bytes.js.map +1 -0
- package/dist/utils/caches.d.cts +98 -0
- package/dist/utils/caches.d.ts +17 -14
- package/dist/utils/caches.js +188 -193
- package/dist/utils/caches.js.map +1 -0
- package/dist/utils/compile-time.d.cts +8 -0
- package/dist/utils/compile-time.d.ts +3 -1
- package/dist/utils/compile-time.js +35 -10
- package/dist/utils/compile-time.js.map +1 -0
- package/dist/utils/crypto.d.cts +8 -0
- package/dist/utils/crypto.d.ts +4 -2
- package/dist/utils/crypto.js +49 -21
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/dates.d.cts +15 -0
- package/dist/utils/dates.d.ts +6 -4
- package/dist/utils/dates.js +83 -105
- package/dist/utils/dates.js.map +1 -0
- package/dist/utils/dom.d.cts +3 -0
- package/dist/utils/dom.d.ts +3 -1
- package/dist/utils/dom.js +35 -7
- package/dist/utils/dom.js.map +1 -0
- package/dist/utils/env.d.cts +9 -0
- package/dist/utils/env.d.ts +6 -4
- package/dist/utils/env.js +70 -43
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/errors.d.cts +223 -0
- package/dist/utils/errors.d.ts +14 -11
- package/dist/utils/errors.js +148 -126
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/fs.d.cts +7 -0
- package/dist/utils/fs.d.ts +5 -3
- package/dist/utils/fs.js +70 -27
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/functions.d.cts +4 -0
- package/dist/utils/functions.d.ts +4 -2
- package/dist/utils/functions.js +35 -18
- package/dist/utils/functions.js.map +1 -0
- package/dist/utils/geo.d.cts +22 -0
- package/dist/utils/geo.d.ts +6 -3
- package/dist/utils/geo.js +39 -9
- package/dist/utils/geo.js.map +1 -0
- package/dist/utils/globals.d.cts +5 -0
- package/dist/utils/globals.d.ts +4 -2
- package/dist/utils/globals.js +41 -14
- package/dist/utils/globals.js.map +1 -0
- package/dist/utils/hashes.d.cts +7 -0
- package/dist/utils/hashes.d.ts +7 -5
- package/dist/utils/hashes.js +87 -41
- package/dist/utils/hashes.js.map +1 -0
- package/dist/utils/html.d.cts +4 -0
- package/dist/utils/html.d.ts +4 -2
- package/dist/utils/html.js +36 -37
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/http.d.cts +43 -0
- package/dist/utils/http.d.ts +6 -4
- package/dist/utils/http.js +83 -83
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/ips.d.cts +6 -0
- package/dist/utils/ips.d.ts +6 -4
- package/dist/utils/ips.js +48 -35
- package/dist/utils/ips.js.map +1 -0
- package/dist/utils/json.d.cts +13 -0
- package/dist/utils/json.d.ts +9 -6
- package/dist/utils/json.js +54 -157
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/jwt.d.cts +44 -0
- package/dist/utils/jwt.d.ts +14 -11
- package/dist/utils/jwt.js +119 -84
- package/dist/utils/jwt.js.map +1 -0
- package/dist/utils/locks.d.cts +15 -0
- package/dist/utils/locks.d.ts +3 -2
- package/dist/utils/locks.js +76 -56
- package/dist/utils/locks.js.map +1 -0
- package/dist/utils/maps.d.cts +59 -0
- package/dist/utils/maps.d.ts +6 -4
- package/dist/utils/maps.js +207 -343
- package/dist/utils/maps.js.map +1 -0
- package/dist/utils/math.d.cts +6 -0
- package/dist/utils/math.d.ts +3 -1
- package/dist/utils/math.js +31 -16
- package/dist/utils/math.js.map +1 -0
- package/dist/utils/node-http.d.cts +15 -0
- package/dist/utils/node-http.d.ts +5 -5
- package/dist/utils/node-http.js +65 -36
- package/dist/utils/node-http.js.map +1 -0
- package/dist/utils/numbers.d.cts +5 -0
- package/dist/utils/numbers.d.ts +5 -3
- package/dist/utils/numbers.js +53 -66
- package/dist/utils/numbers.js.map +1 -0
- package/dist/utils/oauth.d.cts +8 -0
- package/dist/utils/oauth.d.ts +8 -6
- package/dist/utils/oauth.js +37 -4
- package/dist/utils/oauth.js.map +1 -0
- package/dist/utils/objects.d.cts +69 -0
- package/dist/utils/objects.d.ts +37 -32
- package/dist/utils/objects.js +224 -374
- package/dist/utils/objects.js.map +1 -0
- package/dist/utils/passkey.d.cts +1 -0
- package/dist/utils/passkey.d.ts +1 -1
- package/dist/utils/passkey.js +19 -1
- package/dist/utils/passkey.js.map +1 -0
- package/dist/utils/promises.d.cts +74 -0
- package/dist/utils/promises.d.ts +20 -18
- package/dist/utils/promises.js +252 -393
- package/dist/utils/promises.js.map +1 -0
- package/dist/utils/proxies.d.cts +4 -0
- package/dist/utils/proxies.d.ts +4 -2
- package/dist/utils/proxies.js +150 -161
- package/dist/utils/proxies.js.map +1 -0
- package/dist/utils/react.d.cts +25 -0
- package/dist/utils/react.d.ts +9 -6
- package/dist/utils/react.js +88 -134
- package/dist/utils/react.js.map +1 -0
- package/dist/utils/results.d.cts +78 -0
- package/dist/utils/results.d.ts +10 -9
- package/dist/utils/results.js +143 -324
- package/dist/utils/results.js.map +1 -0
- package/dist/utils/sentry.d.cts +5 -0
- package/dist/utils/sentry.d.ts +5 -2
- package/dist/utils/sentry.js +44 -14
- package/dist/utils/sentry.js.map +1 -0
- package/dist/utils/stores.d.cts +102 -0
- package/dist/utils/stores.d.ts +12 -9
- package/dist/utils/stores.js +219 -189
- package/dist/utils/stores.js.map +1 -0
- package/dist/utils/strings.d.cts +72 -0
- package/dist/utils/strings.d.ts +22 -20
- package/dist/utils/strings.js +300 -580
- package/dist/utils/strings.js.map +1 -0
- package/dist/utils/strings.nicify.test.d.cts +2 -0
- package/dist/utils/strings.nicify.test.d.ts +2 -1
- package/dist/utils/strings.nicify.test.js +168 -158
- package/dist/utils/strings.nicify.test.js.map +1 -0
- package/dist/utils/types.d.cts +23 -0
- package/dist/utils/types.d.ts +8 -6
- package/dist/utils/types.js +19 -1
- package/dist/utils/types.js.map +1 -0
- package/dist/utils/unicode.d.cts +3 -0
- package/dist/utils/unicode.d.ts +3 -1
- package/dist/utils/unicode.js +34 -21
- package/dist/utils/unicode.js.map +1 -0
- package/dist/utils/urls.d.cts +20 -0
- package/dist/utils/urls.d.ts +10 -8
- package/dist/utils/urls.js +76 -165
- package/dist/utils/urls.js.map +1 -0
- package/dist/utils/uuids.d.cts +4 -0
- package/dist/utils/uuids.d.ts +4 -2
- package/dist/utils/uuids.js +39 -35
- package/dist/utils/uuids.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// src/utils/errors.tsx
|
|
2
|
+
import { globalVar } from "./globals";
|
|
3
|
+
import { pick } from "./objects";
|
|
4
|
+
import { nicify } from "./strings";
|
|
5
|
+
function throwErr(...args) {
|
|
6
|
+
if (typeof args[0] === "string") {
|
|
7
|
+
throw new StackAssertionError(args[0], args[1]);
|
|
8
|
+
} else if (args[0] instanceof Error) {
|
|
9
|
+
throw args[0];
|
|
10
|
+
} else {
|
|
11
|
+
throw new StatusError(...args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function removeStacktraceNameLine(stack) {
|
|
15
|
+
const addsNameLine = new Error().stack?.startsWith("Error\n");
|
|
16
|
+
return stack.split("\n").slice(addsNameLine ? 1 : 0).join("\n");
|
|
17
|
+
}
|
|
18
|
+
function concatStacktraces(first, ...errors) {
|
|
19
|
+
const addsEmptyLineAtEnd = first.stack?.endsWith("\n");
|
|
20
|
+
const separator = removeStacktraceNameLine(new Error().stack ?? "").split("\n")[0];
|
|
21
|
+
for (const error of errors) {
|
|
22
|
+
const toAppend = removeStacktraceNameLine(error.stack ?? "");
|
|
23
|
+
first.stack += (addsEmptyLineAtEnd ? "" : "\n") + separator + "\n" + toAppend;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var StackAssertionError = class extends Error {
|
|
27
|
+
constructor(message, extraData) {
|
|
28
|
+
const disclaimer = `
|
|
29
|
+
|
|
30
|
+
This is likely an error in Stack. Please make sure you are running the newest version and report it.`;
|
|
31
|
+
super(`${message}${message.endsWith(disclaimer) ? "" : disclaimer}`, pick(extraData ?? {}, ["cause"]));
|
|
32
|
+
this.extraData = extraData;
|
|
33
|
+
Object.defineProperty(this, "customCaptureExtraArgs", {
|
|
34
|
+
get() {
|
|
35
|
+
return [this.extraData];
|
|
36
|
+
},
|
|
37
|
+
enumerable: false
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
StackAssertionError.prototype.name = "StackAssertionError";
|
|
42
|
+
function errorToNiceString(error) {
|
|
43
|
+
if (!(error instanceof Error)) return `${typeof error}<${nicify(error)}>`;
|
|
44
|
+
return nicify(error, { maxDepth: 8 });
|
|
45
|
+
}
|
|
46
|
+
var errorSinks = /* @__PURE__ */ new Set();
|
|
47
|
+
function registerErrorSink(sink) {
|
|
48
|
+
if (errorSinks.has(sink)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
errorSinks.add(sink);
|
|
52
|
+
}
|
|
53
|
+
registerErrorSink((location, error, ...extraArgs) => {
|
|
54
|
+
console.error(
|
|
55
|
+
`\x1B[41mCaptured error in ${location}:`,
|
|
56
|
+
// HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing
|
|
57
|
+
// https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
|
|
58
|
+
errorToNiceString(error),
|
|
59
|
+
...extraArgs,
|
|
60
|
+
"\x1B[0m"
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
registerErrorSink((location, error, ...extraArgs) => {
|
|
64
|
+
globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];
|
|
65
|
+
globalVar.stackCapturedErrors.push({ location, error, extraArgs });
|
|
66
|
+
});
|
|
67
|
+
function captureError(location, error) {
|
|
68
|
+
for (const sink of errorSinks) {
|
|
69
|
+
sink(
|
|
70
|
+
location,
|
|
71
|
+
error,
|
|
72
|
+
...error && (typeof error === "object" || typeof error === "function") && "customCaptureExtraArgs" in error && Array.isArray(error.customCaptureExtraArgs) ? error.customCaptureExtraArgs : []
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
var StatusError = class extends Error {
|
|
77
|
+
constructor(status, message) {
|
|
78
|
+
if (typeof status === "object") {
|
|
79
|
+
message ??= status.message;
|
|
80
|
+
status = status.statusCode;
|
|
81
|
+
}
|
|
82
|
+
super(message);
|
|
83
|
+
this.name = "StatusError";
|
|
84
|
+
this.statusCode = status;
|
|
85
|
+
if (!message) {
|
|
86
|
+
throw new StackAssertionError("StatusError always requires a message unless a Status object is passed", { cause: this });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
isClientError() {
|
|
90
|
+
return this.statusCode >= 400 && this.statusCode < 500;
|
|
91
|
+
}
|
|
92
|
+
isServerError() {
|
|
93
|
+
return !this.isClientError();
|
|
94
|
+
}
|
|
95
|
+
getStatusCode() {
|
|
96
|
+
return this.statusCode;
|
|
97
|
+
}
|
|
98
|
+
getBody() {
|
|
99
|
+
return new TextEncoder().encode(this.message);
|
|
100
|
+
}
|
|
101
|
+
getHeaders() {
|
|
102
|
+
return {
|
|
103
|
+
"Content-Type": ["text/plain; charset=utf-8"]
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
toDescriptiveJson() {
|
|
107
|
+
return {
|
|
108
|
+
status_code: this.getStatusCode(),
|
|
109
|
+
message: this.message,
|
|
110
|
+
headers: this.getHeaders()
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* @deprecated this is not a good way to make status errors human-readable, use toDescriptiveJson instead
|
|
115
|
+
*/
|
|
116
|
+
toHttpJson() {
|
|
117
|
+
return {
|
|
118
|
+
status_code: this.statusCode,
|
|
119
|
+
body: this.message,
|
|
120
|
+
headers: this.getHeaders()
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
StatusError.BadRequest = { statusCode: 400, message: "Bad Request" };
|
|
125
|
+
StatusError.Unauthorized = { statusCode: 401, message: "Unauthorized" };
|
|
126
|
+
StatusError.PaymentRequired = { statusCode: 402, message: "Payment Required" };
|
|
127
|
+
StatusError.Forbidden = { statusCode: 403, message: "Forbidden" };
|
|
128
|
+
StatusError.NotFound = { statusCode: 404, message: "Not Found" };
|
|
129
|
+
StatusError.MethodNotAllowed = { statusCode: 405, message: "Method Not Allowed" };
|
|
130
|
+
StatusError.NotAcceptable = { statusCode: 406, message: "Not Acceptable" };
|
|
131
|
+
StatusError.ProxyAuthenticationRequired = { statusCode: 407, message: "Proxy Authentication Required" };
|
|
132
|
+
StatusError.RequestTimeout = { statusCode: 408, message: "Request Timeout" };
|
|
133
|
+
StatusError.Conflict = { statusCode: 409, message: "Conflict" };
|
|
134
|
+
StatusError.Gone = { statusCode: 410, message: "Gone" };
|
|
135
|
+
StatusError.LengthRequired = { statusCode: 411, message: "Length Required" };
|
|
136
|
+
StatusError.PreconditionFailed = { statusCode: 412, message: "Precondition Failed" };
|
|
137
|
+
StatusError.PayloadTooLarge = { statusCode: 413, message: "Payload Too Large" };
|
|
138
|
+
StatusError.URITooLong = { statusCode: 414, message: "URI Too Long" };
|
|
139
|
+
StatusError.UnsupportedMediaType = { statusCode: 415, message: "Unsupported Media Type" };
|
|
140
|
+
StatusError.RangeNotSatisfiable = { statusCode: 416, message: "Range Not Satisfiable" };
|
|
141
|
+
StatusError.ExpectationFailed = { statusCode: 417, message: "Expectation Failed" };
|
|
142
|
+
StatusError.ImATeapot = { statusCode: 418, message: "I'm a teapot" };
|
|
143
|
+
StatusError.MisdirectedRequest = { statusCode: 421, message: "Misdirected Request" };
|
|
144
|
+
StatusError.UnprocessableEntity = { statusCode: 422, message: "Unprocessable Entity" };
|
|
145
|
+
StatusError.Locked = { statusCode: 423, message: "Locked" };
|
|
146
|
+
StatusError.FailedDependency = { statusCode: 424, message: "Failed Dependency" };
|
|
147
|
+
StatusError.TooEarly = { statusCode: 425, message: "Too Early" };
|
|
148
|
+
StatusError.UpgradeRequired = { statusCode: 426, message: "Upgrade Required" };
|
|
149
|
+
StatusError.PreconditionRequired = { statusCode: 428, message: "Precondition Required" };
|
|
150
|
+
StatusError.TooManyRequests = { statusCode: 429, message: "Too Many Requests" };
|
|
151
|
+
StatusError.RequestHeaderFieldsTooLarge = { statusCode: 431, message: "Request Header Fields Too Large" };
|
|
152
|
+
StatusError.UnavailableForLegalReasons = { statusCode: 451, message: "Unavailable For Legal Reasons" };
|
|
153
|
+
StatusError.InternalServerError = { statusCode: 500, message: "Internal Server Error" };
|
|
154
|
+
StatusError.NotImplemented = { statusCode: 501, message: "Not Implemented" };
|
|
155
|
+
StatusError.BadGateway = { statusCode: 502, message: "Bad Gateway" };
|
|
156
|
+
StatusError.ServiceUnavailable = { statusCode: 503, message: "Service Unavailable" };
|
|
157
|
+
StatusError.GatewayTimeout = { statusCode: 504, message: "Gateway Timeout" };
|
|
158
|
+
StatusError.HTTPVersionNotSupported = { statusCode: 505, message: "HTTP Version Not Supported" };
|
|
159
|
+
StatusError.VariantAlsoNegotiates = { statusCode: 506, message: "Variant Also Negotiates" };
|
|
160
|
+
StatusError.InsufficientStorage = { statusCode: 507, message: "Insufficient Storage" };
|
|
161
|
+
StatusError.LoopDetected = { statusCode: 508, message: "Loop Detected" };
|
|
162
|
+
StatusError.NotExtended = { statusCode: 510, message: "Not Extended" };
|
|
163
|
+
StatusError.NetworkAuthenticationRequired = { statusCode: 511, message: "Network Authentication Required" };
|
|
164
|
+
StatusError.prototype.name = "StatusError";
|
|
165
|
+
export {
|
|
166
|
+
StackAssertionError,
|
|
167
|
+
StatusError,
|
|
168
|
+
captureError,
|
|
169
|
+
concatStacktraces,
|
|
170
|
+
errorToNiceString,
|
|
171
|
+
registerErrorSink,
|
|
172
|
+
throwErr
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/errors.tsx"],"sourcesContent":["import { globalVar } from \"./globals\";\nimport { Json } from \"./json\";\nimport { pick } from \"./objects\";\nimport { nicify } from \"./strings\";\n\n\nexport function throwErr(errorMessage: string, extraData?: any): never;\nexport function throwErr(error: Error): never;\nexport function throwErr(...args: StatusErrorConstructorParameters): never;\nexport function throwErr(...args: any[]): never {\n if (typeof args[0] === \"string\") {\n throw new StackAssertionError(args[0], args[1]);\n } else if (args[0] instanceof Error) {\n throw args[0];\n } else {\n // @ts-expect-error\n throw new StatusError(...args);\n }\n}\n\nfunction removeStacktraceNameLine(stack: string): string {\n // some browsers (eg. Chrome) prepend the stack with an extra line with the error name\n const addsNameLine = new Error().stack?.startsWith(\"Error\\n\");\n return stack.split(\"\\n\").slice(addsNameLine ? 1 : 0).join(\"\\n\");\n}\n\n\n/**\n * Concatenates the (original) stacktraces of the given errors onto the first.\n *\n * Useful when you invoke an async function to receive a promise without awaiting it immediately. Browsers are smart\n * enough to keep track of the call stack in async function calls when you invoke `.then` within the same async tick,\n * but if you don't, the stacktrace will be lost.\n *\n * Here's an example of the unwanted behavior:\n *\n * ```tsx\n * async function log() {\n * await wait(0); // simulate an put the task on the event loop\n * console.log(new Error().stack);\n * }\n *\n * async function main() {\n * await log(); // good; prints both \"log\" and \"main\" on the stacktrace\n * log(); // bad; prints only \"log\" on the stacktrace\n * }\n * ```\n */\nexport function concatStacktraces(first: Error, ...errors: Error[]): void {\n // some browsers (eg. Firefox) add an extra empty line at the end\n const addsEmptyLineAtEnd = first.stack?.endsWith(\"\\n\");\n\n\n // Add a reference to this function itself so that we know that stacktraces were concatenated\n // If you are coming here from a stacktrace, please know that the two parts before and after this line are different\n // stacktraces that were concatenated with concatStacktraces\n const separator = removeStacktraceNameLine(new Error().stack ?? \"\").split(\"\\n\")[0];\n\n\n for (const error of errors) {\n const toAppend = removeStacktraceNameLine(error.stack ?? \"\");\n first.stack += (addsEmptyLineAtEnd ? \"\" : \"\\n\") + separator + \"\\n\" + toAppend;\n }\n}\n\n\nexport class StackAssertionError extends Error {\n constructor(message: string, public readonly extraData?: Record<string, any> & ErrorOptions) {\n const disclaimer = `\\n\\nThis is likely an error in Stack. Please make sure you are running the newest version and report it.`;\n super(`${message}${message.endsWith(disclaimer) ? \"\" : disclaimer}`, pick(extraData ?? {}, [\"cause\"]));\n\n Object.defineProperty(this, \"customCaptureExtraArgs\", {\n get() {\n return [this.extraData];\n },\n enumerable: false,\n });\n }\n}\nStackAssertionError.prototype.name = \"StackAssertionError\";\n\n\nexport function errorToNiceString(error: unknown): string {\n if (!(error instanceof Error)) return `${typeof error}<${nicify(error)}>`;\n return nicify(error, { maxDepth: 8 });\n}\n\n\nconst errorSinks = new Set<(location: string, error: unknown, ...extraArgs: unknown[]) => void>();\nexport function registerErrorSink(sink: (location: string, error: unknown) => void): void {\n if (errorSinks.has(sink)) {\n return;\n }\n errorSinks.add(sink);\n}\nregisterErrorSink((location, error, ...extraArgs) => {\n console.error(\n `\\x1b[41mCaptured error in ${location}:`,\n // HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing\n // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button\n errorToNiceString(error),\n ...extraArgs,\n \"\\x1b[0m\",\n );\n});\nregisterErrorSink((location, error, ...extraArgs) => {\n globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];\n globalVar.stackCapturedErrors.push({ location, error, extraArgs });\n});\n\nexport function captureError(location: string, error: unknown): void {\n for (const sink of errorSinks) {\n sink(\n location,\n error,\n ...error && (typeof error === 'object' || typeof error === 'function') && \"customCaptureExtraArgs\" in error && Array.isArray(error.customCaptureExtraArgs) ? (error.customCaptureExtraArgs as any[]) : [],\n );\n }\n}\n\n\ntype Status = {\n statusCode: number,\n message: string,\n};\n\ntype StatusErrorConstructorParameters =\n| [\n status: Status,\n message?: string\n]\n| [\n statusCode: number | Status,\n message: string,\n];\n\nexport class StatusError extends Error {\n public name = \"StatusError\";\n public readonly statusCode: number;\n\n public static BadRequest = { statusCode: 400, message: \"Bad Request\" };\n public static Unauthorized = { statusCode: 401, message: \"Unauthorized\" };\n public static PaymentRequired = { statusCode: 402, message: \"Payment Required\" };\n public static Forbidden = { statusCode: 403, message: \"Forbidden\" };\n public static NotFound = { statusCode: 404, message: \"Not Found\" };\n public static MethodNotAllowed = { statusCode: 405, message: \"Method Not Allowed\" };\n public static NotAcceptable = { statusCode: 406, message: \"Not Acceptable\" };\n public static ProxyAuthenticationRequired = { statusCode: 407, message: \"Proxy Authentication Required\" };\n public static RequestTimeout = { statusCode: 408, message: \"Request Timeout\" };\n public static Conflict = { statusCode: 409, message: \"Conflict\" };\n public static Gone = { statusCode: 410, message: \"Gone\" };\n public static LengthRequired = { statusCode: 411, message: \"Length Required\" };\n public static PreconditionFailed = { statusCode: 412, message: \"Precondition Failed\" };\n public static PayloadTooLarge = { statusCode: 413, message: \"Payload Too Large\" };\n public static URITooLong = { statusCode: 414, message: \"URI Too Long\" };\n public static UnsupportedMediaType = { statusCode: 415, message: \"Unsupported Media Type\" };\n public static RangeNotSatisfiable = { statusCode: 416, message: \"Range Not Satisfiable\" };\n public static ExpectationFailed = { statusCode: 417, message: \"Expectation Failed\" };\n public static ImATeapot = { statusCode: 418, message: \"I'm a teapot\" };\n public static MisdirectedRequest = { statusCode: 421, message: \"Misdirected Request\" };\n public static UnprocessableEntity = { statusCode: 422, message: \"Unprocessable Entity\" };\n public static Locked = { statusCode: 423, message: \"Locked\" };\n public static FailedDependency = { statusCode: 424, message: \"Failed Dependency\" };\n public static TooEarly = { statusCode: 425, message: \"Too Early\" };\n public static UpgradeRequired = { statusCode: 426, message: \"Upgrade Required\" };\n public static PreconditionRequired = { statusCode: 428, message: \"Precondition Required\" };\n public static TooManyRequests = { statusCode: 429, message: \"Too Many Requests\" };\n public static RequestHeaderFieldsTooLarge = { statusCode: 431, message: \"Request Header Fields Too Large\" };\n public static UnavailableForLegalReasons = { statusCode: 451, message: \"Unavailable For Legal Reasons\" };\n\n public static InternalServerError = { statusCode: 500, message: \"Internal Server Error\" };\n public static NotImplemented = { statusCode: 501, message: \"Not Implemented\" };\n public static BadGateway = { statusCode: 502, message: \"Bad Gateway\" };\n public static ServiceUnavailable = { statusCode: 503, message: \"Service Unavailable\" };\n public static GatewayTimeout = { statusCode: 504, message: \"Gateway Timeout\" };\n public static HTTPVersionNotSupported = { statusCode: 505, message: \"HTTP Version Not Supported\" };\n public static VariantAlsoNegotiates = { statusCode: 506, message: \"Variant Also Negotiates\" };\n public static InsufficientStorage = { statusCode: 507, message: \"Insufficient Storage\" };\n public static LoopDetected = { statusCode: 508, message: \"Loop Detected\" };\n public static NotExtended = { statusCode: 510, message: \"Not Extended\" };\n public static NetworkAuthenticationRequired = { statusCode: 511, message: \"Network Authentication Required\" };\n\n\n constructor(...args: StatusErrorConstructorParameters);\n constructor(\n status: number | Status,\n message?: string,\n ) {\n if (typeof status === \"object\") {\n message ??= status.message;\n status = status.statusCode;\n }\n super(message);\n this.statusCode = status;\n if (!message) {\n throw new StackAssertionError(\"StatusError always requires a message unless a Status object is passed\", { cause: this });\n }\n }\n\n public isClientError() {\n return this.statusCode >= 400 && this.statusCode < 500;\n }\n\n public isServerError() {\n return !this.isClientError();\n }\n\n public getStatusCode(): number {\n return this.statusCode;\n }\n\n public getBody(): Uint8Array {\n return new TextEncoder().encode(this.message);\n }\n\n public getHeaders(): Record<string, string[]> {\n return {\n \"Content-Type\": [\"text/plain; charset=utf-8\"],\n };\n }\n\n public toDescriptiveJson(): Json {\n return {\n status_code: this.getStatusCode(),\n message: this.message,\n headers: this.getHeaders(),\n };\n }\n\n /**\n * @deprecated this is not a good way to make status errors human-readable, use toDescriptiveJson instead\n */\n public toHttpJson(): Json {\n return {\n status_code: this.statusCode,\n body: this.message,\n headers: this.getHeaders(),\n };\n }\n}\nStatusError.prototype.name = \"StatusError\";\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/utils/fs.tsx
|
|
2
|
+
import * as stackFs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
async function list(path2) {
|
|
5
|
+
return await stackFs.promises.readdir(path2);
|
|
6
|
+
}
|
|
7
|
+
async function listRecursively(p, options = {}) {
|
|
8
|
+
const files = await list(p);
|
|
9
|
+
return [
|
|
10
|
+
...(await Promise.all(files.map(async (fileName) => {
|
|
11
|
+
const filePath = path.join(p, fileName);
|
|
12
|
+
if ((await stackFs.promises.stat(filePath)).isDirectory()) {
|
|
13
|
+
return [
|
|
14
|
+
...await listRecursively(filePath, options),
|
|
15
|
+
...options.excludeDirectories ? [] : [filePath]
|
|
16
|
+
];
|
|
17
|
+
} else {
|
|
18
|
+
return [filePath];
|
|
19
|
+
}
|
|
20
|
+
}))).flat()
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
function writeFileSyncIfChanged(path2, content) {
|
|
24
|
+
if (stackFs.existsSync(path2)) {
|
|
25
|
+
const existingContent = stackFs.readFileSync(path2, "utf-8");
|
|
26
|
+
if (existingContent === content) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
stackFs.writeFileSync(path2, content);
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
list,
|
|
34
|
+
listRecursively,
|
|
35
|
+
writeFileSyncIfChanged
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/fs.tsx"],"sourcesContent":["import * as stackFs from \"fs\";\nimport * as path from \"path\";\n\nexport async function list(path: string) {\n return await stackFs.promises.readdir(path);\n}\n\nexport async function listRecursively(p: string, options: { excludeDirectories?: boolean } = {}): Promise<string[]> {\n const files = await list(p);\n return [\n ...(await Promise.all(files.map(async (fileName) => {\n const filePath = path.join(p, fileName);\n if ((await stackFs.promises.stat(filePath)).isDirectory()) {\n return [\n ...(await listRecursively(filePath, options)),\n ...(options.excludeDirectories ? [] : [filePath]),\n ];\n } else {\n return [filePath];\n }\n }))).flat(),\n ];\n}\n\nexport function writeFileSyncIfChanged(path: string, content: string): void {\n if (stackFs.existsSync(path)) {\n const existingContent = stackFs.readFileSync(path, \"utf-8\");\n if (existingContent === content) {\n return;\n }\n }\n stackFs.writeFileSync(path, content);\n}\n"],"mappings":";AAAA,YAAY,aAAa;AACzB,YAAY,UAAU;AAEtB,eAAsB,KAAKA,OAAc;AACvC,SAAO,MAAc,iBAAS,QAAQA,KAAI;AAC5C;AAEA,eAAsB,gBAAgB,GAAW,UAA4C,CAAC,GAAsB;AAClH,QAAM,QAAQ,MAAM,KAAK,CAAC;AAC1B,SAAO;AAAA,IACL,IAAI,MAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,aAAa;AAClD,YAAM,WAAgB,UAAK,GAAG,QAAQ;AACtC,WAAK,MAAc,iBAAS,KAAK,QAAQ,GAAG,YAAY,GAAG;AACzD,eAAO;AAAA,UACL,GAAI,MAAM,gBAAgB,UAAU,OAAO;AAAA,UAC3C,GAAI,QAAQ,qBAAqB,CAAC,IAAI,CAAC,QAAQ;AAAA,QACjD;AAAA,MACF,OAAO;AACL,eAAO,CAAC,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC,CAAC,GAAG,KAAK;AAAA,EACZ;AACF;AAEO,SAAS,uBAAuBA,OAAc,SAAuB;AAC1E,MAAY,mBAAWA,KAAI,GAAG;AAC5B,UAAM,kBAA0B,qBAAaA,OAAM,OAAO;AAC1D,QAAI,oBAAoB,SAAS;AAC/B;AAAA,IACF;AAAA,EACF;AACA,EAAQ,sBAAcA,OAAM,OAAO;AACrC;","names":["path"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/functions.tsx"],"sourcesContent":["export function identity<T>(t: T): T {\n return t;\n}\nundefined?.test(\"identity\", ({ expect }) => {\n expect(identity(1)).toBe(1);\n expect(identity(\"test\")).toBe(\"test\");\n expect(identity(null)).toBe(null);\n expect(identity(undefined)).toBe(undefined);\n const obj = { a: 1 };\n expect(identity(obj)).toBe(obj);\n});\n\nexport function identityArgs<T extends any[]>(...args: T): T {\n return args;\n}\nundefined?.test(\"identityArgs\", ({ expect }) => {\n expect(identityArgs()).toEqual([]);\n expect(identityArgs(1)).toEqual([1]);\n expect(identityArgs(1, 2, 3)).toEqual([1, 2, 3]);\n expect(identityArgs(\"a\", \"b\", \"c\")).toEqual([\"a\", \"b\", \"c\"]);\n expect(identityArgs(null, undefined)).toEqual([null, undefined]);\n});\n"],"mappings":";AAAO,SAAS,SAAY,GAAS;AACnC,SAAO;AACT;AAUO,SAAS,gBAAiC,MAAY;AAC3D,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/utils/geo.tsx
|
|
2
|
+
import { yupNumber, yupObject, yupString } from "../schema-fields";
|
|
3
|
+
var geoInfoSchema = yupObject({
|
|
4
|
+
ip: yupString().defined(),
|
|
5
|
+
countryCode: yupString().nullable(),
|
|
6
|
+
regionCode: yupString().nullable(),
|
|
7
|
+
cityName: yupString().nullable(),
|
|
8
|
+
latitude: yupNumber().nullable(),
|
|
9
|
+
longitude: yupNumber().nullable(),
|
|
10
|
+
tzIdentifier: yupString().nullable()
|
|
11
|
+
});
|
|
12
|
+
export {
|
|
13
|
+
geoInfoSchema
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=geo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/geo.tsx"],"sourcesContent":["\nimport * as yup from \"yup\";\nimport { yupNumber, yupObject, yupString } from \"../schema-fields\";\n\nexport const geoInfoSchema = yupObject({\n ip: yupString().defined(),\n countryCode: yupString().nullable(),\n regionCode: yupString().nullable(),\n cityName: yupString().nullable(),\n latitude: yupNumber().nullable(),\n longitude: yupNumber().nullable(),\n tzIdentifier: yupString().nullable(),\n});\n\nexport type GeoInfo = yup.InferType<typeof geoInfoSchema>;\n\n"],"mappings":";AAEA,SAAS,WAAW,WAAW,iBAAiB;AAEzC,IAAM,gBAAgB,UAAU;AAAA,EACrC,IAAI,UAAU,EAAE,QAAQ;AAAA,EACxB,aAAa,UAAU,EAAE,SAAS;AAAA,EAClC,YAAY,UAAU,EAAE,SAAS;AAAA,EACjC,UAAU,UAAU,EAAE,SAAS;AAAA,EAC/B,UAAU,UAAU,EAAE,SAAS;AAAA,EAC/B,WAAW,UAAU,EAAE,SAAS;AAAA,EAChC,cAAc,UAAU,EAAE,SAAS;AACrC,CAAC;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/utils/globals.tsx
|
|
2
|
+
var globalVar = typeof globalThis !== "undefined" ? globalThis : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : typeof self !== "undefined" ? self : {};
|
|
3
|
+
if (typeof globalThis === "undefined") {
|
|
4
|
+
globalVar.globalThis = globalVar;
|
|
5
|
+
}
|
|
6
|
+
var stackGlobalsSymbol = Symbol.for("__stack-globals");
|
|
7
|
+
globalVar[stackGlobalsSymbol] ??= {};
|
|
8
|
+
function createGlobal(key, init) {
|
|
9
|
+
if (!globalVar[stackGlobalsSymbol][key]) {
|
|
10
|
+
globalVar[stackGlobalsSymbol][key] = init();
|
|
11
|
+
}
|
|
12
|
+
return globalVar[stackGlobalsSymbol][key];
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
createGlobal,
|
|
16
|
+
globalVar
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=globals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/globals.tsx"],"sourcesContent":["const globalVar: any =\n typeof globalThis !== 'undefined' ? globalThis :\n typeof global !== 'undefined' ? global :\n typeof window !== 'undefined' ? window :\n typeof self !== 'undefined' ? self :\n {};\nexport {\n globalVar,\n};\n\nif (typeof globalThis === 'undefined') {\n (globalVar as any).globalThis = globalVar;\n}\n\nconst stackGlobalsSymbol = Symbol.for('__stack-globals');\nglobalVar[stackGlobalsSymbol] ??= {};\n\nexport function createGlobal<T>(key: string, init: () => T) {\n if (!globalVar[stackGlobalsSymbol][key]) {\n globalVar[stackGlobalsSymbol][key] = init();\n }\n return globalVar[stackGlobalsSymbol][key] as T;\n}\n"],"mappings":";AAAA,IAAM,YACJ,OAAO,eAAe,cAAc,aAClC,OAAO,WAAW,cAAc,SAC9B,OAAO,WAAW,cAAc,SAC9B,OAAO,SAAS,cAAc,OAC5B,CAAC;AAKX,IAAI,OAAO,eAAe,aAAa;AACrC,EAAC,UAAkB,aAAa;AAClC;AAEA,IAAM,qBAAqB,OAAO,IAAI,iBAAiB;AACvD,UAAU,kBAAkB,MAAM,CAAC;AAE5B,SAAS,aAAgB,KAAa,MAAe;AAC1D,MAAI,CAAC,UAAU,kBAAkB,EAAE,GAAG,GAAG;AACvC,cAAU,kBAAkB,EAAE,GAAG,IAAI,KAAK;AAAA,EAC5C;AACA,SAAO,UAAU,kBAAkB,EAAE,GAAG;AAC1C;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/utils/hashes.tsx
|
|
2
|
+
import bcrypt from "bcrypt";
|
|
3
|
+
import { StackAssertionError } from "./errors";
|
|
4
|
+
async function sha512(input) {
|
|
5
|
+
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
6
|
+
return new Uint8Array(await crypto.subtle.digest("SHA-512", bytes));
|
|
7
|
+
}
|
|
8
|
+
async function hashPassword(password) {
|
|
9
|
+
const passwordBytes = new TextEncoder().encode(password);
|
|
10
|
+
if (passwordBytes.length >= 72) {
|
|
11
|
+
throw new StackAssertionError(`Password is too long for bcrypt`, { len: passwordBytes.length });
|
|
12
|
+
}
|
|
13
|
+
const salt = await bcrypt.genSalt(10);
|
|
14
|
+
return await bcrypt.hash(password, salt);
|
|
15
|
+
}
|
|
16
|
+
async function comparePassword(password, hash) {
|
|
17
|
+
switch (await getPasswordHashAlgorithm(hash)) {
|
|
18
|
+
case "bcrypt": {
|
|
19
|
+
return await bcrypt.compare(password, hash);
|
|
20
|
+
}
|
|
21
|
+
default: {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function isPasswordHashValid(hash) {
|
|
27
|
+
return !!await getPasswordHashAlgorithm(hash);
|
|
28
|
+
}
|
|
29
|
+
async function getPasswordHashAlgorithm(hash) {
|
|
30
|
+
if (typeof hash !== "string") {
|
|
31
|
+
throw new StackAssertionError(`Passed non-string value to getPasswordHashAlgorithm`, { hash });
|
|
32
|
+
}
|
|
33
|
+
if (hash.match(/^\$2[ayb]\$.{56}$/)) {
|
|
34
|
+
try {
|
|
35
|
+
if (bcrypt.getRounds(hash) > 16) {
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
await bcrypt.compare("any string", hash);
|
|
39
|
+
return "bcrypt";
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.warn(`Error while checking bcrypt password hash. Assuming the hash is invalid`, e);
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
comparePassword,
|
|
50
|
+
getPasswordHashAlgorithm,
|
|
51
|
+
hashPassword,
|
|
52
|
+
isPasswordHashValid,
|
|
53
|
+
sha512
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=hashes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/hashes.tsx"],"sourcesContent":["import bcrypt from 'bcrypt';\nimport { StackAssertionError } from './errors';\n\nexport async function sha512(input: Uint8Array | string): Promise<Uint8Array> {\n const bytes = typeof input === \"string\" ? new TextEncoder().encode(input) : input;\n return new Uint8Array(await crypto.subtle.digest(\"SHA-512\", bytes));\n}\n\nexport async function hashPassword(password: string) {\n const passwordBytes = new TextEncoder().encode(password);\n if (passwordBytes.length >= 72) {\n throw new StackAssertionError(`Password is too long for bcrypt`, { len: passwordBytes.length });\n }\n const salt = await bcrypt.genSalt(10);\n return await bcrypt.hash(password, salt);\n}\n\nexport async function comparePassword(password: string, hash: string): Promise<boolean> {\n switch (await getPasswordHashAlgorithm(hash)) {\n case \"bcrypt\": {\n return await bcrypt.compare(password, hash);\n }\n default: {\n return false;\n }\n }\n}\n\nexport async function isPasswordHashValid(hash: string) {\n return !!(await getPasswordHashAlgorithm(hash));\n}\n\nexport async function getPasswordHashAlgorithm(hash: string): Promise<\"bcrypt\" | undefined> {\n if (typeof hash !== \"string\") {\n throw new StackAssertionError(`Passed non-string value to getPasswordHashAlgorithm`, { hash });\n }\n if (hash.match(/^\\$2[ayb]\\$.{56}$/)) {\n try {\n if (bcrypt.getRounds(hash) > 16) {\n return undefined;\n }\n await bcrypt.compare(\"any string\", hash);\n return \"bcrypt\";\n } catch (e) {\n console.warn(`Error while checking bcrypt password hash. Assuming the hash is invalid`, e);\n return undefined;\n }\n } else {\n return undefined;\n }\n}\n"],"mappings":";AAAA,OAAO,YAAY;AACnB,SAAS,2BAA2B;AAEpC,eAAsB,OAAO,OAAiD;AAC5E,QAAM,QAAQ,OAAO,UAAU,WAAW,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI;AAC5E,SAAO,IAAI,WAAW,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK,CAAC;AACpE;AAEA,eAAsB,aAAa,UAAkB;AACnD,QAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,QAAQ;AACvD,MAAI,cAAc,UAAU,IAAI;AAC9B,UAAM,IAAI,oBAAoB,mCAAmC,EAAE,KAAK,cAAc,OAAO,CAAC;AAAA,EAChG;AACA,QAAM,OAAO,MAAM,OAAO,QAAQ,EAAE;AACpC,SAAO,MAAM,OAAO,KAAK,UAAU,IAAI;AACzC;AAEA,eAAsB,gBAAgB,UAAkB,MAAgC;AACtF,UAAQ,MAAM,yBAAyB,IAAI,GAAG;AAAA,IAC5C,KAAK,UAAU;AACb,aAAO,MAAM,OAAO,QAAQ,UAAU,IAAI;AAAA,IAC5C;AAAA,IACA,SAAS;AACP,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,eAAsB,oBAAoB,MAAc;AACtD,SAAO,CAAC,CAAE,MAAM,yBAAyB,IAAI;AAC/C;AAEA,eAAsB,yBAAyB,MAA6C;AAC1F,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,IAAI,oBAAoB,uDAAuD,EAAE,KAAK,CAAC;AAAA,EAC/F;AACA,MAAI,KAAK,MAAM,mBAAmB,GAAG;AACnC,QAAI;AACF,UAAI,OAAO,UAAU,IAAI,IAAI,IAAI;AAC/B,eAAO;AAAA,MACT;AACA,YAAM,OAAO,QAAQ,cAAc,IAAI;AACvC,aAAO;AAAA,IACT,SAAS,GAAG;AACV,cAAQ,KAAK,2EAA2E,CAAC;AACzF,aAAO;AAAA,IACT;AAAA,EACF,OAAO;AACL,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/utils/html.tsx
|
|
2
|
+
import { templateIdentity } from "./strings";
|
|
3
|
+
function escapeHtml(unsafe) {
|
|
4
|
+
return `${unsafe}`.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5
|
+
}
|
|
6
|
+
function html(strings, ...values) {
|
|
7
|
+
return templateIdentity(strings, ...values.map((v) => escapeHtml(`${v}`)));
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
escapeHtml,
|
|
11
|
+
html
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/html.tsx"],"sourcesContent":["import { templateIdentity } from \"./strings\";\n\nexport function escapeHtml(unsafe: string): string {\n return `${unsafe}`\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\nundefined?.test(\"escapeHtml\", ({ expect }) => {\n // Test with empty string\n expect(escapeHtml(\"\")).toBe(\"\");\n\n // Test with string without special characters\n expect(escapeHtml(\"hello world\")).toBe(\"hello world\");\n\n // Test with special characters\n expect(escapeHtml(\"<div>\")).toBe(\"<div>\");\n expect(escapeHtml(\"a & b\")).toBe(\"a & b\");\n expect(escapeHtml('a \"quoted\" string')).toBe(\"a "quoted" string\");\n expect(escapeHtml(\"it's a test\")).toBe(\"it's a test\");\n\n // Test with multiple special characters\n expect(escapeHtml(\"<a href=\\\"test\\\">It's a link</a>\")).toBe(\n \"<a href="test">It's a link</a>\"\n );\n});\n\nexport function html(strings: TemplateStringsArray, ...values: any[]): string {\n return templateIdentity(strings, ...values.map(v => escapeHtml(`${v}`)));\n}\nundefined?.test(\"html\", ({ expect }) => {\n // Test with no interpolation\n expect(html`simple string`).toBe(\"simple string\");\n\n // Test with string interpolation\n expect(html`Hello, ${\"world\"}!`).toBe(\"Hello, world!\");\n\n // Test with number interpolation\n expect(html`Count: ${42}`).toBe(\"Count: 42\");\n\n // Test with HTML special characters in interpolated values\n expect(html`<div>${\"<script>\"}</div>`).toBe(\"<div><script></div>\");\n\n // Test with multiple interpolations\n expect(html`${1} + ${2} = ${\"<3\"}`).toBe(\"1 + 2 = <3\");\n\n // Test with object interpolation\n const obj = { toString: () => \"<object>\" };\n expect(html`Object: ${obj}`).toBe(\"Object: <object>\");\n});\n"],"mappings":";AAAA,SAAS,wBAAwB;AAE1B,SAAS,WAAW,QAAwB;AACjD,SAAO,GAAG,MAAM,GACb,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAoBO,SAAS,KAAK,YAAkC,QAAuB;AAC5E,SAAO,iBAAiB,SAAS,GAAG,OAAO,IAAI,OAAK,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC;AACzE;","names":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/utils/http.tsx
|
|
2
|
+
import { decodeBase64, encodeBase64, isBase64 } from "./bytes";
|
|
3
|
+
var HTTP_METHODS = {
|
|
4
|
+
"GET": {
|
|
5
|
+
safe: true,
|
|
6
|
+
idempotent: true
|
|
7
|
+
},
|
|
8
|
+
"POST": {
|
|
9
|
+
safe: false,
|
|
10
|
+
idempotent: false
|
|
11
|
+
},
|
|
12
|
+
"PUT": {
|
|
13
|
+
safe: false,
|
|
14
|
+
idempotent: true
|
|
15
|
+
},
|
|
16
|
+
"DELETE": {
|
|
17
|
+
safe: false,
|
|
18
|
+
idempotent: true
|
|
19
|
+
},
|
|
20
|
+
"PATCH": {
|
|
21
|
+
safe: false,
|
|
22
|
+
idempotent: false
|
|
23
|
+
},
|
|
24
|
+
"OPTIONS": {
|
|
25
|
+
safe: true,
|
|
26
|
+
idempotent: true
|
|
27
|
+
},
|
|
28
|
+
"HEAD": {
|
|
29
|
+
safe: true,
|
|
30
|
+
idempotent: true
|
|
31
|
+
},
|
|
32
|
+
"TRACE": {
|
|
33
|
+
safe: true,
|
|
34
|
+
idempotent: true
|
|
35
|
+
},
|
|
36
|
+
"CONNECT": {
|
|
37
|
+
safe: false,
|
|
38
|
+
idempotent: false
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function decodeBasicAuthorizationHeader(value) {
|
|
42
|
+
const [type, encoded, ...rest] = value.split(" ");
|
|
43
|
+
if (rest.length > 0) return null;
|
|
44
|
+
if (!encoded) return null;
|
|
45
|
+
if (type !== "Basic") return null;
|
|
46
|
+
if (!isBase64(encoded)) return null;
|
|
47
|
+
const decoded = new TextDecoder().decode(decodeBase64(encoded));
|
|
48
|
+
const split = decoded.split(":");
|
|
49
|
+
return [split[0], split.slice(1).join(":")];
|
|
50
|
+
}
|
|
51
|
+
function encodeBasicAuthorizationHeader(id, password) {
|
|
52
|
+
if (id.includes(":")) throw new Error("Basic authorization header id cannot contain ':'");
|
|
53
|
+
return `Basic ${encodeBase64(new TextEncoder().encode(`${id}:${password}`))}`;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
HTTP_METHODS,
|
|
57
|
+
decodeBasicAuthorizationHeader,
|
|
58
|
+
encodeBasicAuthorizationHeader
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/http.tsx"],"sourcesContent":["import { decodeBase64, encodeBase64, isBase64 } from \"./bytes\";\n\nexport const HTTP_METHODS = {\n \"GET\": {\n safe: true,\n idempotent: true,\n },\n \"POST\": {\n safe: false,\n idempotent: false,\n },\n \"PUT\": {\n safe: false,\n idempotent: true,\n },\n \"DELETE\": {\n safe: false,\n idempotent: true,\n },\n \"PATCH\": {\n safe: false,\n idempotent: false,\n },\n \"OPTIONS\": {\n safe: true,\n idempotent: true,\n },\n \"HEAD\": {\n safe: true,\n idempotent: true,\n },\n \"TRACE\": {\n safe: true,\n idempotent: true,\n },\n \"CONNECT\": {\n safe: false,\n idempotent: false,\n },\n} as const;\nexport type HttpMethod = keyof typeof HTTP_METHODS;\n\nexport function decodeBasicAuthorizationHeader(value: string): [string, string] | null {\n const [type, encoded, ...rest] = value.split(' ');\n if (rest.length > 0) return null;\n if (!encoded) return null;\n if (type !== 'Basic') return null;\n if (!isBase64(encoded)) return null;\n const decoded = new TextDecoder().decode(decodeBase64(encoded));\n const split = decoded.split(':');\n return [split[0], split.slice(1).join(':')];\n}\nundefined?.test(\"decodeBasicAuthorizationHeader\", ({ expect }) => {\n // Test with valid Basic Authorization header\n const username = \"user\";\n const password = \"pass\";\n const encoded = encodeBasicAuthorizationHeader(username, password);\n expect(decodeBasicAuthorizationHeader(encoded)).toEqual([username, password]);\n\n // Test with password containing colons\n const complexPassword = \"pass:with:colons\";\n const encodedComplex = encodeBasicAuthorizationHeader(username, complexPassword);\n expect(decodeBasicAuthorizationHeader(encodedComplex)).toEqual([username, complexPassword]);\n\n // Test with invalid headers\n expect(decodeBasicAuthorizationHeader(\"NotBasic dXNlcjpwYXNz\")).toBe(null); // Wrong type\n expect(decodeBasicAuthorizationHeader(\"Basic\")).toBe(null); // Missing encoded part\n expect(decodeBasicAuthorizationHeader(\"Basic not-base64\")).toBe(null); // Not base64\n expect(decodeBasicAuthorizationHeader(\"Basic dXNlcjpwYXNz extra\")).toBe(null); // Extra parts\n});\n\nexport function encodeBasicAuthorizationHeader(id: string, password: string): string {\n if (id.includes(':')) throw new Error(\"Basic authorization header id cannot contain ':'\");\n return `Basic ${encodeBase64(new TextEncoder().encode(`${id}:${password}`))}`;\n}\nundefined?.test(\"encodeBasicAuthorizationHeader\", ({ expect }) => {\n // Test with simple username and password\n const encoded = encodeBasicAuthorizationHeader(\"user\", \"pass\");\n expect(encoded).toMatch(/^Basic [A-Za-z0-9+/=]+$/); // Should start with \"Basic \" followed by base64\n\n // Test with empty password\n const encodedEmptyPass = encodeBasicAuthorizationHeader(\"user\", \"\");\n expect(encodedEmptyPass).toMatch(/^Basic [A-Za-z0-9+/=]+$/);\n\n // Test with password containing special characters\n const encodedSpecialChars = encodeBasicAuthorizationHeader(\"user\", \"p@ss!w0rd\");\n expect(encodedSpecialChars).toMatch(/^Basic [A-Za-z0-9+/=]+$/);\n\n // Test with username containing colon should throw\n expect(() => encodeBasicAuthorizationHeader(\"user:name\", \"pass\")).toThrow();\n});\n"],"mappings":";AAAA,SAAS,cAAc,cAAc,gBAAgB;AAE9C,IAAM,eAAe;AAAA,EAC1B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,WAAW;AAAA,IACT,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,WAAW;AAAA,IACT,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AACF;AAGO,SAAS,+BAA+B,OAAwC;AACrF,QAAM,CAAC,MAAM,SAAS,GAAG,IAAI,IAAI,MAAM,MAAM,GAAG;AAChD,MAAI,KAAK,SAAS,EAAG,QAAO;AAC5B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,SAAS,QAAS,QAAO;AAC7B,MAAI,CAAC,SAAS,OAAO,EAAG,QAAO;AAC/B,QAAM,UAAU,IAAI,YAAY,EAAE,OAAO,aAAa,OAAO,CAAC;AAC9D,QAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,SAAO,CAAC,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC;AAC5C;AAoBO,SAAS,+BAA+B,IAAY,UAA0B;AACnF,MAAI,GAAG,SAAS,GAAG,EAAG,OAAM,IAAI,MAAM,kDAAkD;AACxF,SAAO,SAAS,aAAa,IAAI,YAAY,EAAE,OAAO,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAC;AAC7E;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/utils/ips.tsx
|
|
2
|
+
import ipRegex from "ip-regex";
|
|
3
|
+
function isIpAddress(ip) {
|
|
4
|
+
return ipRegex({ exact: true }).test(ip);
|
|
5
|
+
}
|
|
6
|
+
function assertIpAddress(ip) {
|
|
7
|
+
if (!isIpAddress(ip)) {
|
|
8
|
+
throw new Error(`Invalid IP address: ${ip}`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
assertIpAddress,
|
|
13
|
+
isIpAddress
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=ips.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/ips.tsx"],"sourcesContent":["import ipRegex from \"ip-regex\";\n\nexport type Ipv4Address = `${number}.${number}.${number}.${number}`;\nexport type Ipv6Address = string;\n\nexport function isIpAddress(ip: string): ip is Ipv4Address | Ipv6Address {\n return ipRegex({ exact: true }).test(ip);\n}\nundefined?.test(\"isIpAddress\", ({ expect }) => {\n // Test valid IPv4 addresses\n expect(isIpAddress(\"192.168.1.1\")).toBe(true);\n expect(isIpAddress(\"127.0.0.1\")).toBe(true);\n expect(isIpAddress(\"0.0.0.0\")).toBe(true);\n expect(isIpAddress(\"255.255.255.255\")).toBe(true);\n\n // Test valid IPv6 addresses\n expect(isIpAddress(\"::1\")).toBe(true);\n expect(isIpAddress(\"2001:db8::\")).toBe(true);\n expect(isIpAddress(\"2001:db8:85a3:8d3:1319:8a2e:370:7348\")).toBe(true);\n\n // Test invalid IP addresses\n expect(isIpAddress(\"\")).toBe(false);\n expect(isIpAddress(\"not an ip\")).toBe(false);\n expect(isIpAddress(\"256.256.256.256\")).toBe(false);\n expect(isIpAddress(\"192.168.1\")).toBe(false);\n expect(isIpAddress(\"192.168.1.1.1\")).toBe(false);\n expect(isIpAddress(\"2001:db8::xyz\")).toBe(false);\n});\n\nexport function assertIpAddress(ip: string): asserts ip is Ipv4Address | Ipv6Address {\n if (!isIpAddress(ip)) {\n throw new Error(`Invalid IP address: ${ip}`);\n }\n}\nundefined?.test(\"assertIpAddress\", ({ expect }) => {\n // Test with valid IPv4 address\n expect(() => assertIpAddress(\"192.168.1.1\")).not.toThrow();\n\n // Test with valid IPv6 address\n expect(() => assertIpAddress(\"::1\")).not.toThrow();\n\n // Test with invalid IP addresses\n expect(() => assertIpAddress(\"\")).toThrow(\"Invalid IP address: \");\n expect(() => assertIpAddress(\"not an ip\")).toThrow(\"Invalid IP address: not an ip\");\n expect(() => assertIpAddress(\"256.256.256.256\")).toThrow(\"Invalid IP address: 256.256.256.256\");\n expect(() => assertIpAddress(\"192.168.1\")).toThrow(\"Invalid IP address: 192.168.1\");\n});\n"],"mappings":";AAAA,OAAO,aAAa;AAKb,SAAS,YAAY,IAA6C;AACvE,SAAO,QAAQ,EAAE,OAAO,KAAK,CAAC,EAAE,KAAK,EAAE;AACzC;AAsBO,SAAS,gBAAgB,IAAqD;AACnF,MAAI,CAAC,YAAY,EAAE,GAAG;AACpB,UAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AAAA,EAC7C;AACF;","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/utils/json.tsx
|
|
2
|
+
import { Result } from "./results";
|
|
3
|
+
function isJson(value) {
|
|
4
|
+
switch (typeof value) {
|
|
5
|
+
case "object": {
|
|
6
|
+
if (value === null) return true;
|
|
7
|
+
if (Array.isArray(value)) return value.every(isJson);
|
|
8
|
+
return Object.keys(value).every((k) => typeof k === "string") && Object.values(value).every(isJson);
|
|
9
|
+
}
|
|
10
|
+
case "string":
|
|
11
|
+
case "number":
|
|
12
|
+
case "boolean": {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
default: {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function parseJson(json) {
|
|
21
|
+
return Result.fromThrowing(() => JSON.parse(json));
|
|
22
|
+
}
|
|
23
|
+
function stringifyJson(json) {
|
|
24
|
+
return Result.fromThrowing(() => JSON.stringify(json));
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
isJson,
|
|
28
|
+
parseJson,
|
|
29
|
+
stringifyJson
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/json.tsx"],"sourcesContent":["import { Result } from \"./results\";\n\nexport type Json =\n | null\n | boolean\n | number\n | string\n | Json[]\n | { [key: string]: Json };\n\nexport type ReadonlyJson =\n | null\n | boolean\n | number\n | string\n | readonly ReadonlyJson[]\n | { readonly [key: string]: ReadonlyJson };\n\nexport function isJson(value: unknown): value is Json {\n switch (typeof value) {\n case \"object\": {\n if (value === null) return true;\n if (Array.isArray(value)) return value.every(isJson);\n return Object.keys(value).every(k => typeof k === \"string\") && Object.values(value).every(isJson);\n }\n case \"string\":\n case \"number\":\n case \"boolean\": {\n return true;\n }\n default: {\n return false;\n }\n }\n}\nundefined?.test(\"isJson\", ({ expect }) => {\n // Test primitive values\n expect(isJson(null)).toBe(true);\n expect(isJson(true)).toBe(true);\n expect(isJson(false)).toBe(true);\n expect(isJson(123)).toBe(true);\n expect(isJson(\"string\")).toBe(true);\n\n // Test arrays\n expect(isJson([])).toBe(true);\n expect(isJson([1, 2, 3])).toBe(true);\n expect(isJson([\"a\", \"b\", \"c\"])).toBe(true);\n expect(isJson([1, \"a\", true, null])).toBe(true);\n expect(isJson([1, [2, 3], { a: \"b\" }])).toBe(true);\n\n // Test objects\n expect(isJson({})).toBe(true);\n expect(isJson({ a: 1, b: 2 })).toBe(true);\n expect(isJson({ a: \"string\", b: true, c: null })).toBe(true);\n expect(isJson({ a: [1, 2, 3], b: { c: \"d\" } })).toBe(true);\n\n // Test invalid JSON values\n expect(isJson(undefined)).toBe(false);\n expect(isJson(() => {})).toBe(false);\n expect(isJson(Symbol())).toBe(false);\n expect(isJson(BigInt(123))).toBe(false);\n\n // Test arrays with invalid JSON values\n expect(isJson([1, undefined, 3])).toBe(false);\n expect(isJson([1, () => {}, 3])).toBe(false);\n\n // Test objects with invalid JSON values\n expect(isJson({ a: 1, b: undefined })).toBe(false);\n expect(isJson({ a: 1, b: () => {} })).toBe(false);\n});\n\nexport function parseJson(json: string): Result<Json> {\n return Result.fromThrowing(() => JSON.parse(json));\n}\nundefined?.test(\"parseJson\", ({ expect }) => {\n // Test valid JSON strings\n const nullResult = parseJson(\"null\");\n expect(nullResult.status).toBe(\"ok\");\n if (nullResult.status === \"ok\") {\n expect(nullResult.data).toBe(null);\n }\n\n const trueResult = parseJson(\"true\");\n expect(trueResult.status).toBe(\"ok\");\n if (trueResult.status === \"ok\") {\n expect(trueResult.data).toBe(true);\n }\n\n const numberResult = parseJson(\"123\");\n expect(numberResult.status).toBe(\"ok\");\n if (numberResult.status === \"ok\") {\n expect(numberResult.data).toBe(123);\n }\n\n const stringResult = parseJson('\"string\"');\n expect(stringResult.status).toBe(\"ok\");\n if (stringResult.status === \"ok\") {\n expect(stringResult.data).toBe(\"string\");\n }\n\n const emptyArrayResult = parseJson(\"[]\");\n expect(emptyArrayResult.status).toBe(\"ok\");\n if (emptyArrayResult.status === \"ok\") {\n expect(emptyArrayResult.data).toEqual([]);\n }\n\n const arrayResult = parseJson(\"[1,2,3]\");\n expect(arrayResult.status).toBe(\"ok\");\n if (arrayResult.status === \"ok\") {\n expect(arrayResult.data).toEqual([1, 2, 3]);\n }\n\n const emptyObjectResult = parseJson(\"{}\");\n expect(emptyObjectResult.status).toBe(\"ok\");\n if (emptyObjectResult.status === \"ok\") {\n expect(emptyObjectResult.data).toEqual({});\n }\n\n const objectResult = parseJson('{\"a\":1,\"b\":\"string\"}');\n expect(objectResult.status).toBe(\"ok\");\n if (objectResult.status === \"ok\") {\n expect(objectResult.data).toEqual({ a: 1, b: \"string\" });\n }\n\n // Test invalid JSON strings\n expect(parseJson(\"\").status).toBe(\"error\");\n expect(parseJson(\"undefined\").status).toBe(\"error\");\n expect(parseJson(\"{\").status).toBe(\"error\");\n expect(parseJson('{\"a\":1,}').status).toBe(\"error\");\n expect(parseJson(\"function(){}\").status).toBe(\"error\");\n});\n\nexport function stringifyJson(json: Json): Result<string> {\n return Result.fromThrowing(() => JSON.stringify(json));\n}\nundefined?.test(\"stringifyJson\", ({ expect }) => {\n // Test primitive values\n const nullResult = stringifyJson(null);\n expect(nullResult.status).toBe(\"ok\");\n if (nullResult.status === \"ok\") {\n expect(nullResult.data).toBe(\"null\");\n }\n\n const trueResult = stringifyJson(true);\n expect(trueResult.status).toBe(\"ok\");\n if (trueResult.status === \"ok\") {\n expect(trueResult.data).toBe(\"true\");\n }\n\n const numberResult = stringifyJson(123);\n expect(numberResult.status).toBe(\"ok\");\n if (numberResult.status === \"ok\") {\n expect(numberResult.data).toBe(\"123\");\n }\n\n const stringResult = stringifyJson(\"string\");\n expect(stringResult.status).toBe(\"ok\");\n if (stringResult.status === \"ok\") {\n expect(stringResult.data).toBe('\"string\"');\n }\n\n // Test arrays\n const emptyArrayResult = stringifyJson([]);\n expect(emptyArrayResult.status).toBe(\"ok\");\n if (emptyArrayResult.status === \"ok\") {\n expect(emptyArrayResult.data).toBe(\"[]\");\n }\n\n const arrayResult = stringifyJson([1, 2, 3]);\n expect(arrayResult.status).toBe(\"ok\");\n if (arrayResult.status === \"ok\") {\n expect(arrayResult.data).toBe(\"[1,2,3]\");\n }\n\n // Test objects\n const emptyObjectResult = stringifyJson({});\n expect(emptyObjectResult.status).toBe(\"ok\");\n if (emptyObjectResult.status === \"ok\") {\n expect(emptyObjectResult.data).toBe(\"{}\");\n }\n\n const objectResult = stringifyJson({ a: 1, b: \"string\" });\n expect(objectResult.status).toBe(\"ok\");\n if (objectResult.status === \"ok\") {\n expect(objectResult.data).toBe('{\"a\":1,\"b\":\"string\"}');\n }\n\n // Test nested structures\n const nested = { a: [1, 2, 3], b: { c: \"d\" } };\n const nestedResult = stringifyJson(nested);\n expect(nestedResult.status).toBe(\"ok\");\n if (nestedResult.status === \"ok\") {\n expect(nestedResult.data).toBe('{\"a\":[1,2,3],\"b\":{\"c\":\"d\"}}');\n }\n\n // Test circular references (should error)\n const circular: any = { a: 1 };\n circular.self = circular;\n expect(stringifyJson(circular).status).toBe(\"error\");\n});\n"],"mappings":";AAAA,SAAS,cAAc;AAkBhB,SAAS,OAAO,OAA+B;AACpD,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK,UAAU;AACb,UAAI,UAAU,KAAM,QAAO;AAC3B,UAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,MAAM,MAAM;AACnD,aAAO,OAAO,KAAK,KAAK,EAAE,MAAM,OAAK,OAAO,MAAM,QAAQ,KAAK,OAAO,OAAO,KAAK,EAAE,MAAM,MAAM;AAAA,IAClG;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,WAAW;AACd,aAAO;AAAA,IACT;AAAA,IACA,SAAS;AACP,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAqCO,SAAS,UAAU,MAA4B;AACpD,SAAO,OAAO,aAAa,MAAM,KAAK,MAAM,IAAI,CAAC;AACnD;AA2DO,SAAS,cAAc,MAA4B;AACxD,SAAO,OAAO,aAAa,MAAM,KAAK,UAAU,IAAI,CAAC;AACvD;","names":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/utils/jwt.tsx
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
import elliptic from "elliptic";
|
|
4
|
+
import * as jose from "jose";
|
|
5
|
+
import { JOSEError } from "jose/errors";
|
|
6
|
+
import { encodeBase64Url } from "./bytes";
|
|
7
|
+
import { StackAssertionError } from "./errors";
|
|
8
|
+
import { globalVar } from "./globals";
|
|
9
|
+
import { pick } from "./objects";
|
|
10
|
+
var STACK_SERVER_SECRET = process.env.STACK_SERVER_SECRET ?? "";
|
|
11
|
+
try {
|
|
12
|
+
jose.base64url.decode(STACK_SERVER_SECRET);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
throw new Error("STACK_SERVER_SECRET is not valid. Please use the generateKeys script to generate a new secret.");
|
|
15
|
+
}
|
|
16
|
+
async function legacySignGlobalJWT(issuer, payload, expirationTime = "5m") {
|
|
17
|
+
const privateJwk = await jose.importJWK(await getPrivateJwk(STACK_SERVER_SECRET));
|
|
18
|
+
return await new jose.SignJWT(payload).setProtectedHeader({ alg: "ES256" }).setIssuer(issuer).setIssuedAt().setExpirationTime(expirationTime).sign(privateJwk);
|
|
19
|
+
}
|
|
20
|
+
async function legacyVerifyGlobalJWT(issuer, jwt) {
|
|
21
|
+
const jwkSet = jose.createLocalJWKSet(await getPublicJwkSet(STACK_SERVER_SECRET));
|
|
22
|
+
const verified = await jose.jwtVerify(jwt, jwkSet, { issuer });
|
|
23
|
+
return verified.payload;
|
|
24
|
+
}
|
|
25
|
+
async function signJWT(options) {
|
|
26
|
+
const secret = getPerAudienceSecret({ audience: options.audience, secret: STACK_SERVER_SECRET });
|
|
27
|
+
const kid = getKid({ secret });
|
|
28
|
+
const privateJwk = await jose.importJWK(await getPrivateJwk(secret));
|
|
29
|
+
return await new jose.SignJWT(options.payload).setProtectedHeader({ alg: "ES256", kid }).setIssuer(options.issuer).setIssuedAt().setAudience(options.audience).setExpirationTime(options.expirationTime || "5m").sign(privateJwk);
|
|
30
|
+
}
|
|
31
|
+
async function verifyJWT(options) {
|
|
32
|
+
const audience = jose.decodeJwt(options.jwt).aud;
|
|
33
|
+
if (!audience || typeof audience !== "string") {
|
|
34
|
+
throw new JOSEError("Invalid JWT audience");
|
|
35
|
+
}
|
|
36
|
+
const secret = getPerAudienceSecret({ audience, secret: STACK_SERVER_SECRET });
|
|
37
|
+
const jwkSet = jose.createLocalJWKSet(await getPublicJwkSet(secret));
|
|
38
|
+
const verified = await jose.jwtVerify(options.jwt, jwkSet, { issuer: options.issuer });
|
|
39
|
+
return verified.payload;
|
|
40
|
+
}
|
|
41
|
+
async function getPrivateJwk(secret) {
|
|
42
|
+
const secretHash = await globalVar.crypto.subtle.digest("SHA-256", jose.base64url.decode(secret));
|
|
43
|
+
const priv = new Uint8Array(secretHash);
|
|
44
|
+
const ec = new elliptic.ec("p256");
|
|
45
|
+
const key = ec.keyFromPrivate(priv);
|
|
46
|
+
const publicKey = key.getPublic();
|
|
47
|
+
return {
|
|
48
|
+
kty: "EC",
|
|
49
|
+
crv: "P-256",
|
|
50
|
+
alg: "ES256",
|
|
51
|
+
kid: getKid({ secret }),
|
|
52
|
+
d: encodeBase64Url(priv),
|
|
53
|
+
x: encodeBase64Url(publicKey.getX().toBuffer()),
|
|
54
|
+
y: encodeBase64Url(publicKey.getY().toBuffer())
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function getPublicJwkSet(secretOrPrivateJwk) {
|
|
58
|
+
const privateJwk = typeof secretOrPrivateJwk === "string" ? await getPrivateJwk(secretOrPrivateJwk) : secretOrPrivateJwk;
|
|
59
|
+
const jwk = pick(privateJwk, ["kty", "alg", "crv", "x", "y", "kid"]);
|
|
60
|
+
return {
|
|
61
|
+
keys: [jwk]
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function getPerAudienceSecret(options) {
|
|
65
|
+
if (options.audience === "kid") {
|
|
66
|
+
throw new StackAssertionError("You cannot use the 'kid' audience for a per-audience secret, see comment below in jwt.tsx");
|
|
67
|
+
}
|
|
68
|
+
return jose.base64url.encode(
|
|
69
|
+
crypto.createHash("sha256").update(JSON.stringify([options.secret, options.audience])).digest()
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
function getKid(options) {
|
|
73
|
+
return jose.base64url.encode(
|
|
74
|
+
crypto.createHash("sha256").update(JSON.stringify([options.secret, "kid"])).digest()
|
|
75
|
+
).slice(0, 12);
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
getKid,
|
|
79
|
+
getPerAudienceSecret,
|
|
80
|
+
getPrivateJwk,
|
|
81
|
+
getPublicJwkSet,
|
|
82
|
+
legacySignGlobalJWT,
|
|
83
|
+
legacyVerifyGlobalJWT,
|
|
84
|
+
signJWT,
|
|
85
|
+
verifyJWT
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=jwt.js.map
|