From cf28aa58cf36c8f8cc8fd682454b4f9b9531beff Mon Sep 17 00:00:00 2001
From: automated-signal <37887102+automated-signal@users.noreply.github.com>
Date: Mon, 6 Jul 2026 18:19:23 -0500
Subject: [PATCH] Init @signalapp/types package
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
---
.oxlint/rules/enforceFileSuffix.mjs | 2 +
.oxlintrc.json | 5 +-
ACKNOWLEDGMENTS.md | 664 ++++++++++++++++++
package.json | 1 +
package.schema.json | 2 +-
packages/lame/package.json | 1 +
packages/mute-state-change/package.json | 1 +
packages/types/.gitignore | 1 +
packages/types/LICENSE | 661 +++++++++++++++++
packages/types/README.md | 253 +++++++
packages/types/package.json | 51 ++
packages/types/src/Result.std.ts | 51 ++
packages/types/src/_utils/address.std.ts | 43 ++
packages/types/src/_utils/bytes.std.ts | 49 ++
packages/types/src/_utils/datetime.std.ts | 30 +
packages/types/src/_utils/numbers.std.ts | 24 +
packages/types/src/_utils/pni.std.ts | 13 +
.../types/src/datetime/DurationDays.std.ts | 56 ++
packages/types/src/datetime/DurationMs.std.ts | 81 +++
.../types/src/datetime/DurationSecs.std.ts | 76 ++
.../src/datetime/PlainTimeHourMin.std.ts | 51 ++
.../types/src/datetime/TimestampMs.std.ts | 55 ++
.../types/src/datetime/TimestampSecs.std.ts | 49 ++
packages/types/src/encodings/Base64.std.ts | 51 ++
packages/types/src/encodings/Base64Url.std.ts | 51 ++
packages/types/src/encodings/Bytes.std.ts | 35 +
packages/types/src/encodings/Hex.std.ts | 48 ++
packages/types/src/encodings/Json.std.ts | 150 ++++
packages/types/src/encodings/Utf8.std.ts | 20 +
packages/types/src/formats/HexColor.std.ts | 28 +
packages/types/src/formats/HttpUrl.std.ts | 28 +
packages/types/src/formats/LanguageTag.std.ts | 37 +
packages/types/src/formats/MimeType.std.ts | 28 +
packages/types/src/formats/Semver.std.ts | 33 +
packages/types/src/formats/Uuid.std.ts | 43 ++
packages/types/src/index.std.ts | 65 ++
packages/types/src/numbers/BigInt128.std.ts | 38 +
packages/types/src/numbers/BigInt64.std.ts | 38 +
packages/types/src/numbers/BigUint128.std.ts | 38 +
packages/types/src/numbers/BigUint64.std.ts | 38 +
packages/types/src/numbers/Float16.std.ts | 32 +
packages/types/src/numbers/Float32.std.ts | 32 +
packages/types/src/numbers/Float64.std.ts | 28 +
packages/types/src/numbers/Int16.std.ts | 39 +
packages/types/src/numbers/Int32.std.ts | 39 +
packages/types/src/numbers/Int8.std.ts | 39 +
packages/types/src/numbers/Uint16.std.ts | 39 +
packages/types/src/numbers/Uint32.std.ts | 39 +
packages/types/src/numbers/Uint8.std.ts | 39 +
packages/types/src/service/Aci.std.ts | 53 ++
packages/types/src/service/Address.std.ts | 67 ++
packages/types/src/service/AddressInfo.std.ts | 49 ++
packages/types/src/service/DeviceId.std.ts | 34 +
.../types/src/service/DistributionId.std.ts | 53 ++
.../src/service/DistributionListId.std.ts | 53 ++
packages/types/src/service/E164.std.ts | 47 ++
packages/types/src/service/GroupId.std.ts | 52 ++
packages/types/src/service/Pni.std.ts | 64 ++
.../src/service/ReceivedTimestampMs.std.ts | 44 ++
.../types/src/service/SentTimestampMs.std.ts | 44 ++
.../src/service/ServerTimestampMs.std.ts | 44 ++
packages/types/src/service/ServiceId.std.ts | 46 ++
.../types/src/service/StorageItemKey.std.ts | 47 ++
.../src/service/StorageManifestVersion.std.ts | 37 +
packages/types/src/service/UntaggedPni.std.ts | 60 ++
packages/types/src/units/UnitBytes.std.ts | 51 ++
packages/types/src/units/UnitKibibytes.std.ts | 46 ++
packages/types/src/units/UnitKilobytes.std.ts | 46 ++
packages/types/tsconfig.json | 51 ++
packages/types/tsdown.config.mjs | 17 +
packages/windows-ucv/package.json | 2 +-
pnpm-lock.yaml | 620 +++++++++++++++-
.../pinned-messages/PinMessageDialog.dom.tsx | 14 +-
ts/jobs/conversationJobQueue.preload.ts | 20 +-
ts/messageModifiers/PinnedMessages.preload.ts | 11 +-
ts/services/backups/import.preload.ts | 7 +-
.../pinnedMessagesCleanupService.preload.ts | 5 +-
ts/services/retryPlaceholders.std.ts | 5 +-
ts/sql/Interface.std.ts | 11 +-
ts/state/ducks/conversations.preload.ts | 11 +-
.../SignalProtocolStore_test.preload.ts | 35 +-
.../services/retryPlaceholders_test.std.ts | 41 +-
.../sql/server/pinnedMessages_test.node.ts | 7 +-
ts/textsecure/MessageReceiver.preload.ts | 24 +-
ts/textsecure/Types.d.ts | 16 +-
ts/textsecure/messageReceiverEvents.std.ts | 24 +-
ts/textsecure/processDataMessage.preload.ts | 11 +-
ts/types/PinnedMessage.std.ts | 15 +-
ts/util/getPinMessageTarget.preload.ts | 13 +-
ts/util/pinnedMessages.std.ts | 14 +-
90 files changed, 5100 insertions(+), 126 deletions(-)
create mode 100644 packages/types/.gitignore
create mode 100644 packages/types/LICENSE
create mode 100644 packages/types/README.md
create mode 100644 packages/types/package.json
create mode 100644 packages/types/src/Result.std.ts
create mode 100644 packages/types/src/_utils/address.std.ts
create mode 100644 packages/types/src/_utils/bytes.std.ts
create mode 100644 packages/types/src/_utils/datetime.std.ts
create mode 100644 packages/types/src/_utils/numbers.std.ts
create mode 100644 packages/types/src/_utils/pni.std.ts
create mode 100644 packages/types/src/datetime/DurationDays.std.ts
create mode 100644 packages/types/src/datetime/DurationMs.std.ts
create mode 100644 packages/types/src/datetime/DurationSecs.std.ts
create mode 100644 packages/types/src/datetime/PlainTimeHourMin.std.ts
create mode 100644 packages/types/src/datetime/TimestampMs.std.ts
create mode 100644 packages/types/src/datetime/TimestampSecs.std.ts
create mode 100644 packages/types/src/encodings/Base64.std.ts
create mode 100644 packages/types/src/encodings/Base64Url.std.ts
create mode 100644 packages/types/src/encodings/Bytes.std.ts
create mode 100644 packages/types/src/encodings/Hex.std.ts
create mode 100644 packages/types/src/encodings/Json.std.ts
create mode 100644 packages/types/src/encodings/Utf8.std.ts
create mode 100644 packages/types/src/formats/HexColor.std.ts
create mode 100644 packages/types/src/formats/HttpUrl.std.ts
create mode 100644 packages/types/src/formats/LanguageTag.std.ts
create mode 100644 packages/types/src/formats/MimeType.std.ts
create mode 100644 packages/types/src/formats/Semver.std.ts
create mode 100644 packages/types/src/formats/Uuid.std.ts
create mode 100644 packages/types/src/index.std.ts
create mode 100644 packages/types/src/numbers/BigInt128.std.ts
create mode 100644 packages/types/src/numbers/BigInt64.std.ts
create mode 100644 packages/types/src/numbers/BigUint128.std.ts
create mode 100644 packages/types/src/numbers/BigUint64.std.ts
create mode 100644 packages/types/src/numbers/Float16.std.ts
create mode 100644 packages/types/src/numbers/Float32.std.ts
create mode 100644 packages/types/src/numbers/Float64.std.ts
create mode 100644 packages/types/src/numbers/Int16.std.ts
create mode 100644 packages/types/src/numbers/Int32.std.ts
create mode 100644 packages/types/src/numbers/Int8.std.ts
create mode 100644 packages/types/src/numbers/Uint16.std.ts
create mode 100644 packages/types/src/numbers/Uint32.std.ts
create mode 100644 packages/types/src/numbers/Uint8.std.ts
create mode 100644 packages/types/src/service/Aci.std.ts
create mode 100644 packages/types/src/service/Address.std.ts
create mode 100644 packages/types/src/service/AddressInfo.std.ts
create mode 100644 packages/types/src/service/DeviceId.std.ts
create mode 100644 packages/types/src/service/DistributionId.std.ts
create mode 100644 packages/types/src/service/DistributionListId.std.ts
create mode 100644 packages/types/src/service/E164.std.ts
create mode 100644 packages/types/src/service/GroupId.std.ts
create mode 100644 packages/types/src/service/Pni.std.ts
create mode 100644 packages/types/src/service/ReceivedTimestampMs.std.ts
create mode 100644 packages/types/src/service/SentTimestampMs.std.ts
create mode 100644 packages/types/src/service/ServerTimestampMs.std.ts
create mode 100644 packages/types/src/service/ServiceId.std.ts
create mode 100644 packages/types/src/service/StorageItemKey.std.ts
create mode 100644 packages/types/src/service/StorageManifestVersion.std.ts
create mode 100644 packages/types/src/service/UntaggedPni.std.ts
create mode 100644 packages/types/src/units/UnitBytes.std.ts
create mode 100644 packages/types/src/units/UnitKibibytes.std.ts
create mode 100644 packages/types/src/units/UnitKilobytes.std.ts
create mode 100644 packages/types/tsconfig.json
create mode 100644 packages/types/tsdown.config.mjs
diff --git a/.oxlint/rules/enforceFileSuffix.mjs b/.oxlint/rules/enforceFileSuffix.mjs
index 413bb128ec..f926cc05c7 100644
--- a/.oxlint/rules/enforceFileSuffix.mjs
+++ b/.oxlint/rules/enforceFileSuffix.mjs
@@ -145,6 +145,7 @@ const NODE_PACKAGES = new Set([
'svgo',
'synckit',
'tailwindcss',
+ 'tsdown',
'tsx',
'typescript',
'wait-on',
@@ -206,6 +207,7 @@ const STD_PACKAGES = new Set([
'@indutny/sneequals',
'@internationalized/date',
'@react-types/shared',
+ '@signalapp/types',
'@signalapp/minimask',
'@signalapp/parchment-cjs',
'@signalapp/quill-cjs',
diff --git a/.oxlintrc.json b/.oxlintrc.json
index a9bb37d2d2..e387fa8ee7 100644
--- a/.oxlintrc.json
+++ b/.oxlintrc.json
@@ -1763,7 +1763,10 @@
".storybook/**",
"codemods/**",
"danger/**",
- "packages/**",
+ "packages/types/tsdown.config.mjs",
+ "packages/lame/**",
+ "packages/mute-state-change/**",
+ "packages/windows-ucv/**",
"scripts/**",
"test/test.mjs",
".pnpmfile.mjs",
diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md
index 7c5c3bf607..4d8e5a14e5 100644
--- a/ACKNOWLEDGMENTS.md
+++ b/ACKNOWLEDGMENTS.md
@@ -3368,6 +3368,670 @@ Signal Desktop makes use of the following open source projects.
For more information on this, and how to apply and follow the GNU AGPL, see
.
+## @signalapp/types
+
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+ software and other kinds of works, specifically designed to ensure
+ cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+ to take away your freedom to share and change the works. By contrast,
+ our General Public Licenses are intended to guarantee your freedom to
+ share and change all versions of a program--to make sure it remains free
+ software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ them if you wish), that you receive source code or can get it if you
+ want it, that you can change the software or use pieces of it in new
+ free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+ with two steps: (1) assert copyright on the software, and (2) offer
+ you this License which gives you legal permission to copy, distribute
+ and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+ improvements made in alternate versions of the program, if they
+ receive widespread use, become available for other developers to
+ incorporate. Many developers of free software are heartened and
+ encouraged by the resulting cooperation. However, in the case of
+ software used on network servers, this result may fail to come about.
+ The GNU General Public License permits making a modified version and
+ letting the public access it on a server without ever releasing its
+ source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ ensure that, in such cases, the modified source code becomes available
+ to the community. It requires the operator of a network server to
+ provide the source code of the modified version running there to the
+ users of that server. Therefore, public use of a modified version, on
+ a publicly accessible server, gives the public access to the source
+ code of the modified version.
+
+ An older license, called the Affero General Public License and
+ published by Affero, was designed to accomplish similar goals. This is
+ a different license, not a version of the Affero GPL, but Affero has
+ released a new version of the Affero GPL which permits relicensing under
+ this license.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+ works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+ License. Each licensee is addressed as "you". "Licensees" and
+ "recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+ in a fashion requiring copyright permission, other than the making of an
+ exact copy. The resulting work is called a "modified version" of the
+ earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+ on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+ permission, would make you directly or secondarily liable for
+ infringement under applicable copyright law, except executing it on a
+ computer or modifying a private copy. Propagation includes copying,
+ distribution (with or without modification), making available to the
+ public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+ parties to make or receive copies. Mere interaction with a user through
+ a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+ to the extent that it includes a convenient and prominently visible
+ feature that (1) displays an appropriate copyright notice, and (2)
+ tells the user that there is no warranty for the work (except to the
+ extent that warranties are provided), that licensees may convey the
+ work under this License, and how to view a copy of this License. If
+ the interface presents a list of user commands or options, such as a
+ menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+ for making modifications to it. "Object code" means any non-source
+ form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+ standard defined by a recognized standards body, or, in the case of
+ interfaces specified for a particular programming language, one that
+ is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+ than the work as a whole, that (a) is included in the normal form of
+ packaging a Major Component, but which is not part of that Major
+ Component, and (b) serves only to enable use of the work with that
+ Major Component, or to implement a Standard Interface for which an
+ implementation is available to the public in source code form. A
+ "Major Component", in this context, means a major essential component
+ (kernel, window system, and so on) of the specific operating system
+ (if any) on which the executable work runs, or a compiler used to
+ produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+ the source code needed to generate, install, and (for an executable
+ work) run the object code and to modify the work, including scripts to
+ control those activities. However, it does not include the work's
+ System Libraries, or general-purpose tools or generally available free
+ programs which are used unmodified in performing those activities but
+ which are not part of the work. For example, Corresponding Source
+ includes interface definition files associated with source files for
+ the work, and the source code for shared libraries and dynamically
+ linked subprograms that the work is specifically designed to require,
+ such as by intimate data communication or control flow between those
+ subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+ can regenerate automatically from other parts of the Corresponding
+ Source.
+
+ The Corresponding Source for a work in source code form is that
+ same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+ copyright on the Program, and are irrevocable provided the stated
+ conditions are met. This License explicitly affirms your unlimited
+ permission to run the unmodified Program. The output from running a
+ covered work is covered by this License only if the output, given its
+ content, constitutes a covered work. This License acknowledges your
+ rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+ convey, without conditions so long as your license otherwise remains
+ in force. You may convey covered works to others for the sole purpose
+ of having them make modifications exclusively for you, or provide you
+ with facilities for running those works, provided that you comply with
+ the terms of this License in conveying all material for which you do
+ not control copyright. Those thus making or running the covered works
+ for you must do so exclusively on your behalf, under your direction
+ and control, on terms that prohibit them from making any copies of
+ your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+ the conditions stated below. Sublicensing is not allowed; section 10
+ makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+ measure under any applicable law fulfilling obligations under article
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
+ similar laws prohibiting or restricting circumvention of such
+ measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+ circumvention of technological measures to the extent such circumvention
+ is effected by exercising rights under this License with respect to
+ the covered work, and you disclaim any intention to limit operation or
+ modification of the work as a means of enforcing, against the work's
+ users, your or third parties' legal rights to forbid circumvention of
+ technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+ receive it, in any medium, provided that you conspicuously and
+ appropriately publish on each copy an appropriate copyright notice;
+ keep intact all notices stating that this License and any
+ non-permissive terms added in accord with section 7 apply to the code;
+ keep intact all notices of the absence of any warranty; and give all
+ recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+ and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+ produce it from the Program, in the form of source code under the
+ terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+ works, which are not by their nature extensions of the covered work,
+ and which are not combined with it such as to form a larger program,
+ in or on a volume of a storage or distribution medium, is called an
+ "aggregate" if the compilation and its resulting copyright are not
+ used to limit the access or legal rights of the compilation's users
+ beyond what the individual works permit. Inclusion of a covered work
+ in an aggregate does not cause this License to apply to the other
+ parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+ of sections 4 and 5, provided that you also convey the
+ machine-readable Corresponding Source under the terms of this License,
+ in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+ from the Corresponding Source as a System Library, need not be
+ included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+ tangible personal property which is normally used for personal, family,
+ or household purposes, or (2) anything designed or sold for incorporation
+ into a dwelling. In determining whether a product is a consumer product,
+ doubtful cases shall be resolved in favor of coverage. For a particular
+ product received by a particular user, "normally used" refers to a
+ typical or common use of that class of product, regardless of the status
+ of the particular user or of the way in which the particular user
+ actually uses, or expects or is expected to use, the product. A product
+ is a consumer product regardless of whether the product has substantial
+ commercial, industrial or non-consumer uses, unless such uses represent
+ the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+ procedures, authorization keys, or other information required to install
+ and execute modified versions of a covered work in that User Product from
+ a modified version of its Corresponding Source. The information must
+ suffice to ensure that the continued functioning of the modified object
+ code is in no case prevented or interfered with solely because
+ modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+ specifically for use in, a User Product, and the conveying occurs as
+ part of a transaction in which the right of possession and use of the
+ User Product is transferred to the recipient in perpetuity or for a
+ fixed term (regardless of how the transaction is characterized), the
+ Corresponding Source conveyed under this section must be accompanied
+ by the Installation Information. But this requirement does not apply
+ if neither you nor any third party retains the ability to install
+ modified object code on the User Product (for example, the work has
+ been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+ requirement to continue to provide support service, warranty, or updates
+ for a work that has been modified or installed by the recipient, or for
+ the User Product in which it has been modified or installed. Access to a
+ network may be denied when the modification itself materially and
+ adversely affects the operation of the network or violates the rules and
+ protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+ in accord with this section must be in a format that is publicly
+ documented (and with an implementation available to the public in
+ source code form), and must require no special password or key for
+ unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+ License by making exceptions from one or more of its conditions.
+ Additional permissions that are applicable to the entire Program shall
+ be treated as though they were included in this License, to the extent
+ that they are valid under applicable law. If additional permissions
+ apply only to part of the Program, that part may be used separately
+ under those permissions, but the entire Program remains governed by
+ this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+ remove any additional permissions from that copy, or from any part of
+ it. (Additional permissions may be written to require their own
+ removal in certain cases when you modify the work.) You may place
+ additional permissions on material, added by you to a covered work,
+ for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+ add to a covered work, you may (if authorized by the copyright holders of
+ that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+ restrictions" within the meaning of section 10. If the Program as you
+ received it, or any part of it, contains a notice stating that it is
+ governed by this License along with a term that is a further
+ restriction, you may remove that term. If a license document contains
+ a further restriction but permits relicensing or conveying under this
+ License, you may add to a covered work material governed by the terms
+ of that license document, provided that the further restriction does
+ not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+ must place, in the relevant source files, a statement of the
+ additional terms that apply to those files, or a notice indicating
+ where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+ form of a separately written license, or stated as exceptions;
+ the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+ provided under this License. Any attempt otherwise to propagate or
+ modify it is void, and will automatically terminate your rights under
+ this License (including any patent licenses granted under the third
+ paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+ license from a particular copyright holder is reinstated (a)
+ provisionally, unless and until the copyright holder explicitly and
+ finally terminates your license, and (b) permanently, if the copyright
+ holder fails to notify you of the violation by some reasonable means
+ prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+ reinstated permanently if the copyright holder notifies you of the
+ violation by some reasonable means, this is the first time you have
+ received notice of violation of this License (for any work) from that
+ copyright holder, and you cure the violation prior to 30 days after
+ your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+ licenses of parties who have received copies or rights from you under
+ this License. If your rights have been terminated and not permanently
+ reinstated, you do not qualify to receive new licenses for the same
+ material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+ run a copy of the Program. Ancillary propagation of a covered work
+ occurring solely as a consequence of using peer-to-peer transmission
+ to receive a copy likewise does not require acceptance. However,
+ nothing other than this License grants you permission to propagate or
+ modify any covered work. These actions infringe copyright if you do
+ not accept this License. Therefore, by modifying or propagating a
+ covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+ receives a license from the original licensors, to run, modify and
+ propagate that work, subject to this License. You are not responsible
+ for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+ organization, or substantially all assets of one, or subdividing an
+ organization, or merging organizations. If propagation of a covered
+ work results from an entity transaction, each party to that
+ transaction who receives a copy of the work also receives whatever
+ licenses to the work the party's predecessor in interest had or could
+ give under the previous paragraph, plus a right to possession of the
+ Corresponding Source of the work from the predecessor in interest, if
+ the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+ rights granted or affirmed under this License. For example, you may
+ not impose a license fee, royalty, or other charge for exercise of
+ rights granted under this License, and you may not initiate litigation
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ any patent claim is infringed by making, using, selling, offering for
+ sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+ License of the Program or a work on which the Program is based. The
+ work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+ owned or controlled by the contributor, whether already acquired or
+ hereafter acquired, that would be infringed by some manner, permitted
+ by this License, of making, using, or selling its contributor version,
+ but do not include claims that would be infringed only as a
+ consequence of further modification of the contributor version. For
+ purposes of this definition, "control" includes the right to grant
+ patent sublicenses in a manner consistent with the requirements of
+ this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+ patent license under the contributor's essential patent claims, to
+ make, use, sell, offer for sale, import and otherwise run, modify and
+ propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+ agreement or commitment, however denominated, not to enforce a patent
+ (such as an express permission to practice a patent or covenant not to
+ sue for patent infringement). To "grant" such a patent license to a
+ party means to make such an agreement or commitment not to enforce a
+ patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+ and the Corresponding Source of the work is not available for anyone
+ to copy, free of charge and under the terms of this License, through a
+ publicly available network server or other readily accessible means,
+ then you must either (1) cause the Corresponding Source to be so
+ available, or (2) arrange to deprive yourself of the benefit of the
+ patent license for this particular work, or (3) arrange, in a manner
+ consistent with the requirements of this License, to extend the patent
+ license to downstream recipients. "Knowingly relying" means you have
+ actual knowledge that, but for the patent license, your conveying the
+ covered work in a country, or your recipient's use of the covered work
+ in a country, would infringe one or more identifiable patents in that
+ country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+ arrangement, you convey, or propagate by procuring conveyance of, a
+ covered work, and grant a patent license to some of the parties
+ receiving the covered work authorizing them to use, propagate, modify
+ or convey a specific copy of the covered work, then the patent license
+ you grant is automatically extended to all recipients of the covered
+ work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+ the scope of its coverage, prohibits the exercise of, or is
+ conditioned on the non-exercise of one or more of the rights that are
+ specifically granted under this License. You may not convey a covered
+ work if you are a party to an arrangement with a third party that is
+ in the business of distributing software, under which you make payment
+ to the third party based on the extent of your activity of conveying
+ the work, and under which the third party grants, to any of the
+ parties who would receive the covered work from you, a discriminatory
+ patent license (a) in connection with copies of the covered work
+ conveyed by you (or copies made from those copies), or (b) primarily
+ for and in connection with specific products or compilations that
+ contain the covered work, unless you entered into that arrangement,
+ or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+ any implied license or other defenses to infringement that may
+ otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot convey a
+ covered work so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you may
+ not convey it at all. For example, if you agree to terms that obligate you
+ to collect a royalty for further conveying from those to whom you convey
+ the Program, the only way you could satisfy both those terms and this
+ License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+ Program, your modified version must prominently offer all users
+ interacting with it remotely through a computer network (if your version
+ supports such interaction) an opportunity to receive the Corresponding
+ Source of your version by providing access to the Corresponding Source
+ from a network server at no charge, through some standard or customary
+ means of facilitating copying of software. This Corresponding Source
+ shall include the Corresponding Source for any work covered by version 3
+ of the GNU General Public License that is incorporated pursuant to the
+ following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+ permission to link or combine any covered work with a work licensed
+ under version 3 of the GNU General Public License into a single
+ combined work, and to convey the resulting work. The terms of this
+ License will continue to apply to the part which is the covered work,
+ but the work with which it is combined will remain governed by version
+ 3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+ the GNU Affero General Public License from time to time. Such new versions
+ will be similar in spirit to the present version, but may differ in detail to
+ address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+ Program specifies that a certain numbered version of the GNU Affero General
+ Public License "or any later version" applies to it, you have the
+ option of following the terms and conditions either of that numbered
+ version or of any later version published by the Free Software
+ Foundation. If the Program does not specify a version number of the
+ GNU Affero General Public License, you may choose any version ever published
+ by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+ versions of the GNU Affero General Public License can be used, that proxy's
+ public statement of acceptance of a version permanently authorizes you
+ to choose that version for the Program.
+
+ Later license versions may give you additional or different
+ permissions. However, no additional obligations are imposed on any
+ author or copyright holder as a result of your choosing to follow a
+ later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+ above cannot be given local legal effect according to their terms,
+ reviewing courts shall apply local law that most closely approximates
+ an absolute waiver of all civil liability in connection with the
+ Program, unless a warranty or assumption of liability accompanies a
+ copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make it
+ free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+ to attach them to the start of each source file to most effectively
+ state the exclusion of warranty; and each file should have at least
+ the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+ Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+ network, you should also make sure that it provides a way for users to
+ get its source. For example, if your program is a web application, its
+ interface could display a "Source" link that leads users to an archive
+ of the code. There are many ways you could offer source, and different
+ solutions will be better for different programs; see section 13 for the
+ specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
+ For more information on this, and how to apply and follow the GNU AGPL, see
+ .
+
## @signalapp/windows-ucv
GNU AFFERO GENERAL PUBLIC LICENSE
diff --git a/package.json b/package.json
index 61fed4539d..5a9fa4f88a 100644
--- a/package.json
+++ b/package.json
@@ -121,6 +121,7 @@
"dependencies": {
"@indutny/mac-screen-share": "1.2.5",
"@indutny/simple-windows-notifications": "2.0.21",
+ "@signalapp/types": "workspace:*",
"@signalapp/libsignal-client": "0.96.3",
"@signalapp/mute-state-change": "workspace:*",
"@signalapp/ringrtc": "2.69.4",
diff --git a/package.schema.json b/package.schema.json
index 4761d2ebfa..03d2430804 100644
--- a/package.schema.json
+++ b/package.schema.json
@@ -7,7 +7,7 @@
"type": "object",
"properties": {
"build": {
- "$ref": "./node_modules/app-builder-lib/scheme.json"
+ "$ref": "https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json"
}
}
}
diff --git a/packages/lame/package.json b/packages/lame/package.json
index 6a2f5ef495..f0337e31df 100644
--- a/packages/lame/package.json
+++ b/packages/lame/package.json
@@ -1,4 +1,5 @@
{
+ "private": true,
"name": "@signalapp/lame",
"description": "LAME MP3 Encoder bindings for Node.js",
"version": "1.0.0",
diff --git a/packages/mute-state-change/package.json b/packages/mute-state-change/package.json
index ec45211cc1..f0c6510698 100644
--- a/packages/mute-state-change/package.json
+++ b/packages/mute-state-change/package.json
@@ -1,4 +1,5 @@
{
+ "private": true,
"name": "@signalapp/mute-state-change",
"description": "ScreenCaptureKit bindings for Node.js",
"version": "1.0.0",
diff --git a/packages/types/.gitignore b/packages/types/.gitignore
new file mode 100644
index 0000000000..1521c8b765
--- /dev/null
+++ b/packages/types/.gitignore
@@ -0,0 +1 @@
+dist
diff --git a/packages/types/LICENSE b/packages/types/LICENSE
new file mode 100644
index 0000000000..be3f7b28e5
--- /dev/null
+++ b/packages/types/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/packages/types/README.md b/packages/types/README.md
new file mode 100644
index 0000000000..a12cb5c682
--- /dev/null
+++ b/packages/types/README.md
@@ -0,0 +1,253 @@
+
+
+
+# @signalapp/types
+
+This package provides shared opaque and utility types and related helper
+functions for use across different Signal libraries and desktop apps.
+
+```ts
+import { Aci, SentTimestampMs, DurationSecs } from '@signalapp/types';
+
+export type PinnedMessage = Readonly<{
+ targetSentTimestamp: SentTimestampMs;
+ targetAuthorAci: Aci;
+ pinDuration: DurationSecs;
+}>;
+```
+
+## API
+
+```ts
+import type { Tagged } from 'type-fest';
+
+// Result
+type Result = Result.Ok | Result.Err;
+type Result.Ok = Readonly<{ ok: true; value: T; error?: never; }>;
+type Result.Err = Readonly<{ ok: false; value?: never; error: E; }>;
+
+// Numbers
+type Uint8 = Tagged;
+type Uint16 = Tagged;
+type Uint32 = Tagged;
+type BigUint64 = Tagged;
+type BigUint128 = Tagged;
+type Int8 = Tagged;
+type Int16 = Tagged;
+type Int32 = Tagged;
+type BigInt64 = Tagged;
+type BigInt128 = Tagged;
+type Float16 = Tagged;
+type Float32 = Tagged;
+type Float64 = Tagged;
+
+// Units
+type UnitBytes = Tagged;;
+type UnitKilobytes = Tagged;
+type UnitKibibytes = Tagged;
+
+// Datetime
+type TimestampMs = Tagged;
+type TimestampSecs = Tagged;
+type DurationMs = Tagged;
+type DurationSecs = Tagged;
+type DurationDays = Tagged;
+type PlainTimeHourMin = Tagged;
+
+// Encodings
+type Bytes = Uint8Array;
+type Bytes.Of = Tagged;
+type Base64 = Tagged;
+type Base64.Of = Tagged;
+type Base64Url = Tagged;
+type Base64Url.Of = Tagged;
+type Hex = Tagged;
+type Hex.Of = Tagged;
+type Json = Tagged;
+type Json.Of = Tagged;
+type JsonPrimitive = null | boolean | number | string;
+type JsonArray = Array | ReadonlyArray;
+type JsonObject = { [Key in string]: JsonValue };
+type JsonValue = JsonPrimitive | JsonArray | JsonObject;
+type Utf8.Of = Tagged;
+
+// Formats
+type HexColor = Tagged<`#${string}`, 'HexColor'>;
+type HttpUrl = Tagged;
+type LanguageTag = Tagged;
+type MimeType = Tagged<`${string}/${string}`, 'MimeType'>;
+type Semver = Tagged;
+type Uuid = Tagged;
+
+// Service
+type E164 = E164.Decoded;
+type E164.Opaque = Tagged<`+${string}`, 'E164'>;
+type E164.Encoded = Utf8.Of;
+type E164.Decoded = Bytes.Of;
+
+type Aci = Aci.Decoded;
+type Aci.Opaque = Tagged;
+type Aci.Decoded = Utf8.Of;
+type Aci.Encoded = Bytes.Of;
+
+type Pni = Utf8.Of;
+type Pni.Opaque = Tagged<`PNI:${Uuid}`, 'Pni'>;
+type Pni.Decoded = Utf8.Of;
+type Pni.Encoded = Bytes.Of;
+
+type UntaggedPni = UntaggedPni.Decoded;
+type UntaggedPni.Opaque = Tagged;
+type UntaggedPni.Decoded = Utf8.Of;
+type UntaggedPni.Encoded = Bytes.Of;
+
+type ServiceId = ServiceId.Decoded;
+type ServiceId.Decoded = Aci | Pni;
+type ServiceId.Encoded = Bytes.Of;
+
+type DeviceId = Tagged;
+
+type Address = Address.Decoded;
+type Address.Opaque = Tagged<`${ServiceId}.${DeviceId}`, 'Address'>;
+type Address.Decoded = Utf8.Of;
+type Address.Encoded = Bytes.Of;
+
+type AddressInfo = Tagged;
+type AddressInfo.Params = Readonly<{ serviceId: ServiceId; deviceId: DeviceId; }>;
+
+type DistributionId = Utf8.Of;
+type DistributionId.Opaque = Tagged;
+
+type DistributionId = DistributionId.Decoded;
+type DistributionId.Opaque = Tagged;
+type DistributionId.Decoded = Utf8.Of;
+type DistributionId.Encoded = Bytes.Of;
+
+type GroupId = GroupId.Decoded;
+type GroupId.Opaque = Tagged;
+type GroupId.Decoded = Base64.Of;
+type GroupId.Encoded = Bytes.Of;
+
+type DistributionListId = DistributionListId.Decoded;
+type DistributionListId.Opaque = Tagged;
+type DistributionListId.Decoded = Utf8.Of;
+type DistributionListId.Encoded = Bytes.Of;
+
+type SentTimestampMs = Tagged;
+type ServerTimestampMs = Tagged;
+type ReceivedTimestampMs = Tagged;
+
+type StorageManifestVersion = Tagged;
+
+type StorageItemKey = StorageItemKey.Decoded;
+type StorageItemKey.Opaque = Tagged;
+type StorageItemKey.Decoded = Base64.Of;
+type StorageItemKey.Encoded = Bytes.Of;
+```
+
+### Schemas
+
+Almost all of these types provide Zod schemas:
+
+```ts
+import { Aci, SentTimestampMs, DurationSecs } from '@signalapp/types';
+
+export const PinnedMessageSchema = z.object({
+ targetSentTimestamp: SentTimestampMs.Schema,
+ targetAuthorAci: Aci.Schema,
+ pinDuration: DurationSecs.Schema,
+});
+```
+
+### Helpers
+
+Types have helpers for casting loosely typed data to strict types:
+
+> Note: You should prefer to use the most specific `from*` method that you can,
+> it will generally have less runtime cost checking the type is valid.
+
+```ts
+Aci.isValid(input: string): input is Aci; // boolean
+Aci.fromUuid(input: Uuid): Aci; // throws if invalid
+Aci.fromString(input: string): Aci; // throws if invalid
+```
+
+### Encodings
+
+Encodings have special `.Of` types to represent internal opaque
+types:
+
+```ts
+// Maybe this just represents some random number generation that we should not be aware of
+export type MyOpaqueType = Tagged;
+
+export function decode(input: Bytes.Of): Base64.Of {
+ return Base64.fromBytes(input);
+}
+
+export function encode(input: Bytes.Of): Base64.Of {
+ return Base64.toBytes(input);
+}
+```
+
+Many of the "service" types use these `.Of` types to wrap their own
+internal `Opaque` type with expected encodings along with `encode` and `decode`
+helpers:
+
+```ts
+export type StorageItemKey = StorageItemKey.Decoded;
+
+export namespace StorageItemKey {
+ type Opaque = Tagged;
+
+ export type Decoded = Base64.Of;
+ export type Encoded = Bytes.Of;
+
+ export function decode(input: Encoded): StorageItemKey {
+ return Base64.fromBytes(input);
+ }
+
+ export function encode(input: StorageItemKey): Encoded {
+ return Base64.toBytes(input);
+ }
+}
+```
+
+## Future Ideas
+
+- General:
+ - [ ] `NonEmpty`
+ - [ ] `NonZero`
+- Units:
+ - [ ] `Dimension`
+ - [ ] `Width`
+ - [ ] `Height`
+- Formats:
+ - [ ] `BlurHash`
+ - [ ] `RegionId`
+ - [ ] `CurrencyCode`
+ - [ ] `Email`
+- File System:
+ - [ ] `FileName`
+ - [ ] `FilePath`
+ - [ ] `FileExtension`
+- Net:
+ - [ ] `BasicAuth`
+ - [ ] `IpV4`
+ - [ ] `IpV6`
+ - [ ] `IpAddr`
+ - [ ] `Domain/Hostname`
+ - [ ] `Protocol`
+ - [ ] `Port`
+- Service:
+ - [ ] `RegistrationId`
+ - [ ] `ServerGuid`
+ - [ ] `ProfileKey`
+ - [ ] `ProfileKeyVersion
+ - [ ] `Username`
+ - [ ] `ReportingToken`
+ - [ ] `GroupVersion`
+ - [ ] `MasterKey`
+ - [ ] `PublicParams`
+ - [ ] `SecretParams`
+ - [ ] `GroupInviteLinkPassword`
+ - [ ] `UserText` / `TrustedText`
diff --git a/packages/types/package.json b/packages/types/package.json
new file mode 100644
index 0000000000..6d035f5e7c
--- /dev/null
+++ b/packages/types/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "@signalapp/types",
+ "version": "0.0.0",
+ "license": "AGPL-3.0-only",
+ "author": {
+ "name": "Signal Messenger, LLC",
+ "email": "support@signal.org"
+ },
+ "type": "module",
+ "sideEffects": false,
+ "source": "src/index.std.ts",
+ "main": "dist/index.std.cjs",
+ "module": "dist/index.std.mjs",
+ "types": "dist/index.std.d.mts",
+ "files": [
+ "dist"
+ ],
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.std.d.mts",
+ "default": "./dist/index.std.mjs"
+ },
+ "require": {
+ "types": "./dist/index.std.d.cts",
+ "default": "./dist/index.std.cjs"
+ }
+ }
+ },
+ "engines": {
+ "node": ">=24.17.0"
+ },
+ "scripts": {
+ "check": "tsgo --noEmit",
+ "build": "tsdown",
+ "prepare": "pnpm run build"
+ },
+ "dependencies": {
+ "buffer": "6.0.3",
+ "semver": "7.7.4",
+ "type-fest": "5.5.0",
+ "uuid": "13.0.0",
+ "zod": "4.3.6"
+ },
+ "devDependencies": {
+ "@arethetypeswrong/core": "0.18.4",
+ "@typescript/native-preview": "7.0.0-dev.20260515.1",
+ "publint": "0.3.21",
+ "tsdown": "0.22.3"
+ }
+}
diff --git a/packages/types/src/Result.std.ts b/packages/types/src/Result.std.ts
new file mode 100644
index 0000000000..c9d08f7af2
--- /dev/null
+++ b/packages/types/src/Result.std.ts
@@ -0,0 +1,51 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+/**
+ * A discriminated union representing either success ({@link Result.Ok}) or failure ({@link Result.Err}).
+ * @public
+ */
+export type Result = Result.Ok | Result.Err;
+
+export namespace Result {
+ /**
+ * Successful result containing a value.
+ * @public
+ */
+ export type Ok = Readonly<{
+ ok: true;
+ value: T;
+ error?: never;
+ }>;
+
+ /**
+ * Failed result containing an error.
+ * @public
+ */
+ export type Err = Readonly<{
+ ok: false;
+ value?: never;
+ error: E;
+ }>;
+
+ /** @public */
+ export function ok(value: T): Ok {
+ return { ok: true, value };
+ }
+
+ /** @public */
+ export function err(error: E): Err {
+ return { ok: false, error };
+ }
+
+ /** @public */
+ export async function fromPromise(
+ promise: Promise
+ ): Promise> {
+ try {
+ return ok(await promise);
+ } catch (error) {
+ return err(error);
+ }
+ }
+}
diff --git a/packages/types/src/_utils/address.std.ts b/packages/types/src/_utils/address.std.ts
new file mode 100644
index 0000000000..0972a44206
--- /dev/null
+++ b/packages/types/src/_utils/address.std.ts
@@ -0,0 +1,43 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import { Result } from '../Result.std.ts';
+import { ServiceId } from '../service/ServiceId.std.ts';
+import { safeParseNumber } from './numbers.std.ts';
+import { Uint32 } from '../numbers/Uint32.std.ts';
+import { DeviceId } from '../service/DeviceId.std.ts';
+import type { AddressInfo } from '../service/AddressInfo.std.ts';
+
+export function parseAddress(input: string): Result {
+ const parts = input.split('.');
+ if (parts.length !== 2) {
+ return Result.err('must have format "."');
+ }
+
+ const [serviceId, deviceIdStr] = parts;
+ if (serviceId == null || serviceId.length === 0) {
+ return Result.err('missing service id');
+ }
+
+ if (!ServiceId.isValid(serviceId)) {
+ return Result.err('invalid service id');
+ }
+
+ if (deviceIdStr == null || deviceIdStr.length === 0) {
+ return Result.err('missing device id');
+ }
+
+ const deviceId = safeParseNumber(deviceIdStr);
+ if (deviceId == null) {
+ return Result.err('device id is not a number');
+ }
+
+ if (!Uint32.isValid(deviceId)) {
+ return Result.err('device id is not a valid uint32');
+ }
+
+ if (!DeviceId.isValid(deviceId)) {
+ return Result.err('invalid device id');
+ }
+
+ return Result.ok({ serviceId, deviceId });
+}
diff --git a/packages/types/src/_utils/bytes.std.ts b/packages/types/src/_utils/bytes.std.ts
new file mode 100644
index 0000000000..bbe9ba17dd
--- /dev/null
+++ b/packages/types/src/_utils/bytes.std.ts
@@ -0,0 +1,49 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+// oxlint-disable-next-line unicorn/prefer-node-protocol
+import { Buffer } from 'buffer';
+import type { Bytes } from '../encodings/Bytes.std.ts';
+
+/**
+ * TODO: Once upgrading to Node 25+ we can replace Buffer with Uint8Array methods.
+ */
+
+/** Future: `new TextDecoder().decode(input)` */
+export function TextDecoderDecode(input: Bytes): string {
+ return Buffer.from(input).toString('utf8');
+}
+
+/** Future: `new TextEncoder().encode(input)` */
+export function TextEncoderEncode(input: string): Bytes {
+ return Buffer.from(input, 'utf8');
+}
+
+/** Future: `input.toBase64()` */
+export function Uint8ArrayToBase64(input: Bytes): string {
+ return Buffer.from(input).toString('base64');
+}
+
+/** Future: `Uint8Array.fromBase64(input)` */
+export function Uint8ArrayFromBase64(input: string): Bytes {
+ return Buffer.from(input, 'base64');
+}
+
+/** Future: `input.toBase64({ alphabet: 'base64url', omitPadding: true })` */
+export function Uint8ArrayToBase64Url(input: Bytes): string {
+ return Buffer.from(input).toString('base64url');
+}
+
+/** Future: `Uint8Array.fromBase64(input, { alphabet: 'base64url' })` */
+export function Uint8ArrayFromBase64Url(input: string): Bytes {
+ return Buffer.from(input, 'base64url');
+}
+
+/** Future: `input.toHex()` */
+export function Uint8ArrayToHex(input: Bytes): string {
+ return Buffer.from(input).toString('hex');
+}
+
+/** Future: `Uint8Array.fromHex(input)` */
+export function Uint8ArrayFromHex(input: string): Bytes {
+ return Buffer.from(input, 'hex');
+}
diff --git a/packages/types/src/_utils/datetime.std.ts b/packages/types/src/_utils/datetime.std.ts
new file mode 100644
index 0000000000..6c0537043c
--- /dev/null
+++ b/packages/types/src/_utils/datetime.std.ts
@@ -0,0 +1,30 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+export const MIN_SAFE_DATE = -8_640_000_000_000_000;
+export const MAX_SAFE_DATE = 8_640_000_000_000_000;
+
+const MS_PER_SEC = 1000;
+const MS_PER_MIN: number = 60 * MS_PER_SEC;
+const MS_PER_HOUR: number = 60 * MS_PER_MIN;
+const MS_PER_DAY: number = 24 * MS_PER_HOUR;
+
+const SECS_PER_MIN = 60;
+const SECS_PER_HOUR: number = 60 * SECS_PER_MIN;
+const SECS_PER_DAY: number = 24 * SECS_PER_HOUR;
+
+export const msToSecsInt = (ms: number): number => Math.trunc(ms / MS_PER_SEC);
+export const msToDaysInt = (ms: number): number => Math.trunc(ms / MS_PER_DAY);
+
+export const secsToMs = (seconds: number): number => seconds * MS_PER_SEC;
+export const secsToDays = (secs: number): number =>
+ Math.trunc(secs / SECS_PER_DAY);
+
+export const minsToMs = (minutes: number): number => minutes * MS_PER_MIN;
+export const minsToSecs = (mins: number): number => mins * SECS_PER_MIN;
+
+export const hoursToMs = (hours: number): number => hours * MS_PER_HOUR;
+export const hoursToSecs = (hours: number): number => hours * SECS_PER_HOUR;
+
+export const daysToMs = (days: number): number => days * MS_PER_DAY;
+export const daysToSecs = (days: number): number => days * SECS_PER_DAY;
diff --git a/packages/types/src/_utils/numbers.std.ts b/packages/types/src/_utils/numbers.std.ts
new file mode 100644
index 0000000000..746be966a1
--- /dev/null
+++ b/packages/types/src/_utils/numbers.std.ts
@@ -0,0 +1,24 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+const MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
+
+export function bigIntToNumber(input: bigint): number {
+ if (input > MAX_SAFE_INTEGER_BIGINT) {
+ throw new TypeError('must be <= MAX_SAFE_INTEGER');
+ }
+
+ return Number(input);
+}
+
+export function safeParseNumber(input: string): number | null {
+ const trimmed = input.trim();
+ if (trimmed === '') {
+ return null;
+ }
+ const parsed = Number(input);
+ if (!Number.isFinite(parsed)) {
+ return null;
+ }
+ return parsed;
+}
diff --git a/packages/types/src/_utils/pni.std.ts b/packages/types/src/_utils/pni.std.ts
new file mode 100644
index 0000000000..c9c96f6e94
--- /dev/null
+++ b/packages/types/src/_utils/pni.std.ts
@@ -0,0 +1,13 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+export const PNI_PREFIX = 'PNI:';
+
+const PNI_PREFIX_REGEX = /^PNI:/;
+
+export function stripPniPrefix(input: string): string {
+ if (!input.startsWith(PNI_PREFIX)) {
+ throw new TypeError('missing pni prefix');
+ }
+ return input.replace(PNI_PREFIX_REGEX, '');
+}
diff --git a/packages/types/src/datetime/DurationDays.std.ts b/packages/types/src/datetime/DurationDays.std.ts
new file mode 100644
index 0000000000..2c2fd8b68c
--- /dev/null
+++ b/packages/types/src/datetime/DurationDays.std.ts
@@ -0,0 +1,56 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { Uint32 } from '../numbers/Uint32.std.ts';
+import type { DurationMs } from './DurationMs.std.ts';
+import type { DurationSecs } from './DurationSecs.std.ts';
+import { msToDaysInt, secsToDays } from '../_utils/datetime.std.ts';
+
+/**
+ * Duration in days (bounded to `Uint32` range).
+ * @public
+ */
+export type DurationDays = Tagged;
+
+export namespace DurationDays {
+ /** @public */
+ export const DAY = 1 as DurationDays;
+ /** @public */
+ export const SEVEN_DAYS = (DAY * 7) as DurationDays; // "1 week"
+ /** @public */
+ export const TWENTY_EIGHT_DAYS = (DAY * 28) as DurationDays; // "4 weeks"
+ /** @public */
+ export const THIRTY_DAYS = (DAY * 30) as DurationDays; // "1 month"
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ Uint32.Schema,
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is DurationDays {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUint32(input: Uint32): DurationDays {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromNumber(input: number): DurationDays {
+ return fromUint32(Uint32.fromNumber(input));
+ }
+
+ /** @public */
+ export function fromDurationMs(input: DurationMs): DurationDays {
+ return fromNumber(msToDaysInt(input));
+ }
+
+ /** @public */
+ export function fromDurationSecs(input: DurationSecs): DurationDays {
+ return fromNumber(secsToDays(input));
+ }
+}
diff --git a/packages/types/src/datetime/DurationMs.std.ts b/packages/types/src/datetime/DurationMs.std.ts
new file mode 100644
index 0000000000..2582c93ca3
--- /dev/null
+++ b/packages/types/src/datetime/DurationMs.std.ts
@@ -0,0 +1,81 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { Uint32 } from '../numbers/Uint32.std.ts';
+import type { DurationSecs } from './DurationSecs.std.ts';
+import type { DurationDays } from './DurationDays.std.ts';
+import {
+ daysToMs,
+ hoursToMs,
+ minsToMs,
+ secsToMs,
+} from '../_utils/datetime.std.ts';
+
+/**
+ * Duration in milliseconds (bounded to `Uint32` range).
+ * @public
+ */
+export type DurationMs = Tagged;
+
+export namespace DurationMs {
+ /** @public */
+ export const SECOND = 1000 as DurationMs;
+ /** @public */
+ export const MINUTE = (1000 * 60) as DurationMs;
+ /** @public */
+ export const HOUR = (MINUTE * 60) as DurationMs;
+ /** @public */
+ export const DAY = (HOUR * 24) as DurationMs;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ Uint32.Schema,
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is DurationMs {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUint32(input: Uint32): DurationMs {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromMilliseconds(input: number): DurationMs {
+ return fromUint32(Uint32.fromNumber(input));
+ }
+
+ /** @public */
+ export function fromSeconds(input: number): DurationMs {
+ return fromMilliseconds(secsToMs(input));
+ }
+
+ /** @public */
+ export function fromMinutes(input: number): DurationMs {
+ return fromMilliseconds(minsToMs(input));
+ }
+
+ /** @public */
+ export function fromHours(input: number): DurationMs {
+ return fromMilliseconds(hoursToMs(input));
+ }
+
+ /** @public */
+ export function fromDays(input: number): DurationMs {
+ return fromMilliseconds(daysToMs(input));
+ }
+
+ /** @public */
+ export function fromDurationSecs(input: DurationSecs): DurationMs {
+ return fromMilliseconds(secsToMs(input));
+ }
+
+ /** @public */
+ export function fromDurationDays(input: DurationDays): DurationMs {
+ return fromMilliseconds(daysToMs(input));
+ }
+}
diff --git a/packages/types/src/datetime/DurationSecs.std.ts b/packages/types/src/datetime/DurationSecs.std.ts
new file mode 100644
index 0000000000..fd1556b3ee
--- /dev/null
+++ b/packages/types/src/datetime/DurationSecs.std.ts
@@ -0,0 +1,76 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { Uint32 } from '../numbers/Uint32.std.ts';
+import type { DurationMs } from './DurationMs.std.ts';
+import type { DurationDays } from './DurationDays.std.ts';
+import {
+ daysToSecs,
+ hoursToSecs,
+ minsToSecs,
+ msToSecsInt,
+} from '../_utils/datetime.std.ts';
+
+/**
+ * Duration in seconds (bounded to `Uint32` range).
+ * @public
+ */
+export type DurationSecs = Tagged;
+
+export namespace DurationSecs {
+ /** @public */
+ export const SECOND = 1 as DurationSecs;
+ /** @public */
+ export const MINUTE = (SECOND * 60) as DurationSecs;
+ /** @public */
+ export const HOUR = (MINUTE * 60) as DurationSecs;
+ /** @public */
+ export const DAY = (HOUR * 24) as DurationSecs;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ Uint32.Schema,
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is DurationSecs {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUint32(input: Uint32): DurationSecs {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromSeconds(input: number): DurationSecs {
+ return fromUint32(Uint32.fromNumber(input));
+ }
+
+ /** @public */
+ export function fromMinutes(input: number): DurationSecs {
+ return fromSeconds(minsToSecs(input));
+ }
+
+ /** @public */
+ export function fromHours(input: number): DurationSecs {
+ return fromSeconds(hoursToSecs(input));
+ }
+
+ /** @public */
+ export function fromDays(input: number): DurationSecs {
+ return fromSeconds(daysToSecs(input));
+ }
+
+ /** @public */
+ export function fromDurationMs(input: DurationMs): DurationSecs {
+ return fromSeconds(msToSecsInt(input));
+ }
+
+ /** @public */
+ export function fromDurationDays(input: DurationDays): DurationSecs {
+ return fromSeconds(daysToSecs(input));
+ }
+}
diff --git a/packages/types/src/datetime/PlainTimeHourMin.std.ts b/packages/types/src/datetime/PlainTimeHourMin.std.ts
new file mode 100644
index 0000000000..92544dbf1d
--- /dev/null
+++ b/packages/types/src/datetime/PlainTimeHourMin.std.ts
@@ -0,0 +1,51 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { Uint32 } from '../numbers/Uint32.std.ts';
+
+const MIN = 0;
+const MAX = 2359;
+const MINS_MAX = 59;
+
+function getMins(input: number): number {
+ return input % 100;
+}
+
+function isPlainTimeHourMin(input: number): input is PlainTimeHourMin {
+ return (
+ Number.isInteger(input) &&
+ input >= MIN &&
+ input <= MAX &&
+ getMins(input) <= MINS_MAX
+ );
+}
+
+/**
+ * 24-hour clock time as a 4-digit integer (0000–2359).
+ * @public
+ */
+export type PlainTimeHourMin = Tagged;
+
+export namespace PlainTimeHourMin {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ Uint32.Schema,
+ z.custom(isPlainTimeHourMin)
+ );
+
+ /** @public */
+ export function isValid(input: number): input is PlainTimeHourMin {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUint32(input: Uint32): PlainTimeHourMin {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromNumber(input: number): PlainTimeHourMin {
+ return fromUint32(Uint32.fromNumber(input));
+ }
+}
diff --git a/packages/types/src/datetime/TimestampMs.std.ts b/packages/types/src/datetime/TimestampMs.std.ts
new file mode 100644
index 0000000000..88aa505781
--- /dev/null
+++ b/packages/types/src/datetime/TimestampMs.std.ts
@@ -0,0 +1,55 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import {
+ MAX_SAFE_DATE,
+ MIN_SAFE_DATE,
+ secsToMs,
+} from '../_utils/datetime.std.ts';
+import type { TimestampSecs } from './TimestampSecs.std.ts';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Unix timestamp in milliseconds.
+ * @public
+ */
+export type TimestampMs = Tagged;
+
+export namespace TimestampMs {
+ /** @public */
+ export const MIN = MIN_SAFE_DATE as TimestampMs;
+ /** @public */
+ export const MAX = MAX_SAFE_DATE as TimestampMs;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is TimestampMs {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): TimestampMs {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): TimestampMs {
+ return fromNumber(bigIntToNumber(input));
+ }
+
+ /** @public */
+ export function fromTimestampSecs(input: TimestampSecs): TimestampMs {
+ return fromNumber(secsToMs(input));
+ }
+
+ /** @public */
+ export function now(): TimestampMs {
+ return fromNumber(Date.now());
+ }
+}
diff --git a/packages/types/src/datetime/TimestampSecs.std.ts b/packages/types/src/datetime/TimestampSecs.std.ts
new file mode 100644
index 0000000000..689edcaad3
--- /dev/null
+++ b/packages/types/src/datetime/TimestampSecs.std.ts
@@ -0,0 +1,49 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import {
+ MAX_SAFE_DATE,
+ MIN_SAFE_DATE,
+ msToSecsInt,
+} from '../_utils/datetime.std.ts';
+import type { TimestampMs } from './TimestampMs.std.ts';
+
+/**
+ * Unix timestamp in seconds.
+ * @public
+ */
+export type TimestampSecs = Tagged;
+
+export namespace TimestampSecs {
+ /** @public */
+ export const MIN = msToSecsInt(MIN_SAFE_DATE) as TimestampSecs;
+ /** @public */
+ export const MAX = msToSecsInt(MAX_SAFE_DATE) as TimestampSecs;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is TimestampSecs {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): TimestampSecs {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromTimestampMs(input: TimestampMs): TimestampSecs {
+ return fromNumber(msToSecsInt(input));
+ }
+
+ /** @public */
+ export function now(): TimestampSecs {
+ return fromNumber(msToSecsInt(Date.now()));
+ }
+}
diff --git a/packages/types/src/encodings/Base64.std.ts b/packages/types/src/encodings/Base64.std.ts
new file mode 100644
index 0000000000..fc1e26aaec
--- /dev/null
+++ b/packages/types/src/encodings/Base64.std.ts
@@ -0,0 +1,51 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import type { Bytes } from './Bytes.std.ts';
+import {
+ Uint8ArrayFromBase64,
+ Uint8ArrayToBase64,
+} from '../_utils/bytes.std.ts';
+
+/**
+ * Base64-encoded string.
+ * @public
+ */
+export type Base64 = Tagged;
+
+export namespace Base64 {
+ /** @public */
+ export type Of = Tagged;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(z.base64()),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is Base64 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): Base64 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBytes(input: Bytes.Of): Of;
+ export function fromBytes(input: Bytes): Base64;
+ export function fromBytes(input: Bytes): Base64 {
+ return Uint8ArrayToBase64(input) as Base64;
+ }
+
+ /** @public */
+ export function toBytes(input: Of): Bytes.Of;
+ export function toBytes(input: Base64): Bytes;
+ export function toBytes(input: Base64): Bytes {
+ return Uint8ArrayFromBase64(input);
+ }
+}
diff --git a/packages/types/src/encodings/Base64Url.std.ts b/packages/types/src/encodings/Base64Url.std.ts
new file mode 100644
index 0000000000..2b03ec5267
--- /dev/null
+++ b/packages/types/src/encodings/Base64Url.std.ts
@@ -0,0 +1,51 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import type { Bytes } from './Bytes.std.ts';
+import {
+ Uint8ArrayFromBase64Url,
+ Uint8ArrayToBase64Url,
+} from '../_utils/bytes.std.ts';
+
+/**
+ * Base64URL-encoded string (URL-safe variant using `-` and `_` instead of `+` and `/`).
+ * @public
+ */
+export type Base64Url = Tagged;
+
+export namespace Base64Url {
+ /** @public */
+ export type Of = Tagged;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(z.base64url()),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is Base64Url {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): Base64Url {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBytes(input: Bytes.Of): Of;
+ export function fromBytes(input: Bytes): Base64Url;
+ export function fromBytes(input: Bytes): Base64Url {
+ return Uint8ArrayToBase64Url(input) as Base64Url;
+ }
+
+ /** @public */
+ export function toBytes(input: Of): Bytes.Of;
+ export function toBytes(input: Base64Url): Bytes;
+ export function toBytes(input: Base64Url): Bytes {
+ return Uint8ArrayFromBase64Url(input);
+ }
+}
diff --git a/packages/types/src/encodings/Bytes.std.ts b/packages/types/src/encodings/Bytes.std.ts
new file mode 100644
index 0000000000..fe3ebb7c2a
--- /dev/null
+++ b/packages/types/src/encodings/Bytes.std.ts
@@ -0,0 +1,35 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+type MaybeSharedBytes = Uint8Array;
+
+/**
+ * A `Uint8Array` backed by a standard (non-shared) `ArrayBuffer`.
+ * @public
+ */
+export type Bytes = Uint8Array;
+
+export namespace Bytes {
+ /** @public */
+ export type Of = Tagged;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.instanceof(Uint8Array),
+ z.custom(input => {
+ return input.buffer instanceof ArrayBuffer;
+ })
+ );
+
+ /** @public */
+ export function isValid(input: MaybeSharedBytes): input is Bytes {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromMaybeSharedBytes(input: MaybeSharedBytes): Bytes {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/encodings/Hex.std.ts b/packages/types/src/encodings/Hex.std.ts
new file mode 100644
index 0000000000..1007cd3cf5
--- /dev/null
+++ b/packages/types/src/encodings/Hex.std.ts
@@ -0,0 +1,48 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import type { Bytes } from './Bytes.std.ts';
+import { Uint8ArrayFromHex, Uint8ArrayToHex } from '../_utils/bytes.std.ts';
+
+/**
+ * Hexadecimal-encoded string.
+ * @public
+ */
+export type Hex = Tagged;
+
+export namespace Hex {
+ /** @public */
+ export type Of = Tagged;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(z.hex()),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is Hex {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): Hex {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBytes(input: Bytes.Of): Of;
+ export function fromBytes(input: Bytes): Hex;
+ export function fromBytes(input: Bytes): Hex {
+ return Uint8ArrayToHex(input) as Hex;
+ }
+
+ /** @public */
+ export function toBytes(input: Of): Bytes.Of;
+ export function toBytes(input: Hex): Bytes;
+ export function toBytes(input: Hex): Bytes {
+ return Uint8ArrayFromHex(input);
+ }
+}
diff --git a/packages/types/src/encodings/Json.std.ts b/packages/types/src/encodings/Json.std.ts
new file mode 100644
index 0000000000..e514fab6fa
--- /dev/null
+++ b/packages/types/src/encodings/Json.std.ts
@@ -0,0 +1,150 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * A string containing valid JSON
+ * @public
+ */
+export type Json = Tagged;
+
+/**
+ * A JSON primitive value: `null`, `boolean`, `number`, or `string`.
+ * @public
+ */
+export type JsonPrimitive = null | boolean | number | string;
+
+/**
+ * A JSON array.
+ * @public
+ */
+export type JsonArray = Array | ReadonlyArray;
+
+/**
+ * A JSON object with string keys.
+ * @public
+ */
+export type JsonObject = { [Key in string]: JsonValue };
+
+/**
+ * Any valid JSON value.
+ * @public
+ */
+export type JsonValue = JsonPrimitive | JsonArray | JsonObject;
+
+export namespace Json {
+ /** @public */
+ export type Of = Tagged;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(
+ z.superRefine((input, ctx) => {
+ try {
+ JSON.parse(input);
+ } catch (error) {
+ ctx.issues.push({
+ code: 'custom',
+ message: error instanceof Error ? error.message : 'invalid json',
+ input,
+ });
+ }
+ })
+ ),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is Json {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): Json {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function stringify(input: T): Of;
+ export function stringify(input: JsonValue): Json;
+ export function stringify(input: JsonValue): Json {
+ return JSON.stringify(input) as Json;
+ }
+
+ /** @public */
+ export function parse(input: Of): T;
+ export function parse(input: Json): JsonValue;
+ export function parse(input: Json): JsonValue {
+ return JSON.parse(input);
+ }
+}
+
+export namespace JsonPrimitive {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.union([
+ z.null(),
+ z.boolean(),
+ z.number(),
+ z.string(),
+ ]);
+
+ /** @public */
+ export function isValid(input: unknown): input is JsonPrimitive {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUnknown(input: unknown): JsonPrimitive {
+ return Schema.parse(input);
+ }
+}
+
+export namespace JsonArray {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.array(z.json());
+
+ /** @public */
+ export function isValid(input: unknown): input is JsonArray {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUnknown(input: unknown): JsonArray {
+ return Schema.parse(input);
+ }
+}
+
+export namespace JsonObject {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.record(
+ z.string(),
+ z.json()
+ );
+
+ /** @public */
+ export function isValid(input: unknown): input is JsonObject {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUnknown(input: unknown): JsonObject {
+ return Schema.parse(input);
+ }
+}
+
+export namespace JsonValue {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.json();
+
+ /** @public */
+ export function isValid(input: unknown): input is JsonValue {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromUnknown(input: unknown): JsonValue {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/encodings/Utf8.std.ts b/packages/types/src/encodings/Utf8.std.ts
new file mode 100644
index 0000000000..177c948093
--- /dev/null
+++ b/packages/types/src/encodings/Utf8.std.ts
@@ -0,0 +1,20 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import type { Bytes } from './Bytes.std.ts';
+import { TextDecoderDecode, TextEncoderEncode } from '../_utils/bytes.std.ts';
+
+export namespace Utf8 {
+ /** @public */
+ export type Of = Tagged;
+
+ /** @public */
+ export function fromBytes(input: Bytes.Of): Of {
+ return TextDecoderDecode(input) as Of;
+ }
+
+ /** @public */
+ export function toBytes(input: Of): Bytes.Of {
+ return TextEncoderEncode(input) as Bytes.Of;
+ }
+}
diff --git a/packages/types/src/formats/HexColor.std.ts b/packages/types/src/formats/HexColor.std.ts
new file mode 100644
index 0000000000..1252f96dc1
--- /dev/null
+++ b/packages/types/src/formats/HexColor.std.ts
@@ -0,0 +1,28 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * CSS hex color string starting with `#` (e.g., `"#FFFFFF"`).
+ * @public
+ */
+export type HexColor = Tagged<`#${string}`, 'HexColor'>;
+
+export namespace HexColor {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(z.startsWith('#')),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is HexColor {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): HexColor {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/formats/HttpUrl.std.ts b/packages/types/src/formats/HttpUrl.std.ts
new file mode 100644
index 0000000000..8c845b14b2
--- /dev/null
+++ b/packages/types/src/formats/HttpUrl.std.ts
@@ -0,0 +1,28 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * HTTP or HTTPS URL.
+ * @public
+ */
+export type HttpUrl = Tagged;
+
+export namespace HttpUrl {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(z.httpUrl()),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is HttpUrl {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): HttpUrl {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/formats/LanguageTag.std.ts b/packages/types/src/formats/LanguageTag.std.ts
new file mode 100644
index 0000000000..b4a0bdafef
--- /dev/null
+++ b/packages/types/src/formats/LanguageTag.std.ts
@@ -0,0 +1,37 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+function isLanguageTag(input: string): input is LanguageTag {
+ try {
+ new Intl.Locale(input);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+/**
+ * BCP 47 language tag (Ex: `"en-US"`).
+ * @public
+ */
+export type LanguageTag = Tagged;
+
+export namespace LanguageTag {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string(),
+ z.custom(isLanguageTag, 'must be valid language tag')
+ );
+
+ /** @public */
+ export function isValid(input: string): input is LanguageTag {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): LanguageTag {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/formats/MimeType.std.ts b/packages/types/src/formats/MimeType.std.ts
new file mode 100644
index 0000000000..c71a6f8cd0
--- /dev/null
+++ b/packages/types/src/formats/MimeType.std.ts
@@ -0,0 +1,28 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * MIME type string (Ex: `"application/json"`).
+ * @public
+ */
+export type MimeType = Tagged<`${string}/${string}`, 'MimeType'>;
+
+export namespace MimeType {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string().check(z.includes('/')),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: string): input is MimeType {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): MimeType {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/formats/Semver.std.ts b/packages/types/src/formats/Semver.std.ts
new file mode 100644
index 0000000000..e1ce487b1f
--- /dev/null
+++ b/packages/types/src/formats/Semver.std.ts
@@ -0,0 +1,33 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import semverValid from 'semver/functions/valid';
+
+function isSemver(input: string): input is Semver {
+ return semverValid(input) != null;
+}
+
+/**
+ * Semantic version string (Ex: `"1.2.3"`).
+ * @public
+ */
+export type Semver = Tagged;
+
+export namespace Semver {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string(),
+ z.custom(isSemver)
+ );
+
+ /** @public */
+ export function isValid(input: string): input is Semver {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): Semver {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/formats/Uuid.std.ts b/packages/types/src/formats/Uuid.std.ts
new file mode 100644
index 0000000000..bb4491a2f2
--- /dev/null
+++ b/packages/types/src/formats/Uuid.std.ts
@@ -0,0 +1,43 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import * as uuid from 'uuid';
+
+function isUuid(input: string): input is Uuid {
+ return uuid.validate(input);
+}
+
+/**
+ * UUID string (Ex: `"00000000-0000-4000-0000-000000000000"`)
+ * @public
+ */
+export type Uuid = Tagged;
+
+export namespace Uuid {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.string(),
+ z.custom(isUuid)
+ );
+
+ /** @public */
+ export function isValid(input: string): input is Uuid {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromString(input: string): Uuid {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function createV4(): Uuid {
+ return uuid.v4() as Uuid;
+ }
+
+ /** @public */
+ export function createV7(): Uuid {
+ return uuid.v7() as Uuid;
+ }
+}
diff --git a/packages/types/src/index.std.ts b/packages/types/src/index.std.ts
new file mode 100644
index 0000000000..fe25213d00
--- /dev/null
+++ b/packages/types/src/index.std.ts
@@ -0,0 +1,65 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+export { Result } from './Result.std.ts';
+
+export { Uint8 } from './numbers/Uint8.std.ts';
+export { Uint16 } from './numbers/Uint16.std.ts';
+export { Uint32 } from './numbers/Uint32.std.ts';
+export { BigUint64 } from './numbers/BigUint64.std.ts';
+export { BigUint128 } from './numbers/BigUint128.std.ts';
+export { Int8 } from './numbers/Int8.std.ts';
+export { Int16 } from './numbers/Int16.std.ts';
+export { Int32 } from './numbers/Int32.std.ts';
+export { BigInt64 } from './numbers/BigInt64.std.ts';
+export { BigInt128 } from './numbers/BigInt128.std.ts';
+export { Float16 } from './numbers/Float16.std.ts';
+export { Float32 } from './numbers/Float32.std.ts';
+export { Float64 } from './numbers/Float64.std.ts';
+
+export { UnitBytes } from './units/UnitBytes.std.ts';
+export { UnitKilobytes } from './units/UnitKilobytes.std.ts';
+export { UnitKibibytes } from './units/UnitKibibytes.std.ts';
+
+export { TimestampMs } from './datetime/TimestampMs.std.ts';
+export { TimestampSecs } from './datetime/TimestampSecs.std.ts';
+export { DurationMs } from './datetime/DurationMs.std.ts';
+export { DurationSecs } from './datetime/DurationSecs.std.ts';
+export { DurationDays } from './datetime/DurationDays.std.ts';
+export { PlainTimeHourMin } from './datetime/PlainTimeHourMin.std.ts';
+
+export { Bytes } from './encodings/Bytes.std.ts';
+export { Base64 } from './encodings/Base64.std.ts';
+export { Base64Url } from './encodings/Base64Url.std.ts';
+export { Hex } from './encodings/Hex.std.ts';
+export {
+ Json,
+ JsonPrimitive,
+ JsonArray,
+ JsonObject,
+ JsonValue,
+} from './encodings/Json.std.ts';
+
+export { HexColor } from './formats/HexColor.std.ts';
+export { HttpUrl } from './formats/HttpUrl.std.ts';
+export { LanguageTag } from './formats/LanguageTag.std.ts';
+export { MimeType } from './formats/MimeType.std.ts';
+export { Semver } from './formats/Semver.std.ts';
+export { Uuid } from './formats/Uuid.std.ts';
+
+export { E164 } from './service/E164.std.ts';
+export { Aci } from './service/Aci.std.ts';
+export { Pni } from './service/Pni.std.ts';
+export { UntaggedPni } from './service/UntaggedPni.std.ts';
+export { ServiceId } from './service/ServiceId.std.ts';
+export { DeviceId } from './service/DeviceId.std.ts';
+export { Address } from './service/Address.std.ts';
+export { AddressInfo } from './service/AddressInfo.std.ts';
+export { DistributionId } from './service/DistributionId.std.ts';
+export { GroupId } from './service/GroupId.std.ts';
+export { DistributionListId } from './service/DistributionListId.std.ts';
+export { SentTimestampMs } from './service/SentTimestampMs.std.ts';
+export { ServerTimestampMs } from './service/ServerTimestampMs.std.ts';
+export { ReceivedTimestampMs } from './service/ReceivedTimestampMs.std.ts';
+export { StorageManifestVersion } from './service/StorageManifestVersion.std.ts';
+export { StorageItemKey } from './service/StorageItemKey.std.ts';
diff --git a/packages/types/src/numbers/BigInt128.std.ts b/packages/types/src/numbers/BigInt128.std.ts
new file mode 100644
index 0000000000..8527b82291
--- /dev/null
+++ b/packages/types/src/numbers/BigInt128.std.ts
@@ -0,0 +1,38 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * Signed 128-bit integer
+ * @public
+ */
+export type BigInt128 = Tagged;
+
+export namespace BigInt128 {
+ /** @public */
+ export const MIN = -(2n ** 127n) as BigInt128;
+ /** @public */
+ export const MAX = (2n ** 127n - 1n) as BigInt128;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.bigint().check(z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: bigint): input is BigInt128 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): BigInt128 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromNumber(input: number): BigInt128 {
+ return fromBigInt(BigInt(input));
+ }
+}
diff --git a/packages/types/src/numbers/BigInt64.std.ts b/packages/types/src/numbers/BigInt64.std.ts
new file mode 100644
index 0000000000..14e8406bf3
--- /dev/null
+++ b/packages/types/src/numbers/BigInt64.std.ts
@@ -0,0 +1,38 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * Signed 64-bit integer
+ * @public
+ */
+export type BigInt64 = Tagged;
+
+export namespace BigInt64 {
+ /** @public */
+ export const MIN = -(2n ** 63n) as BigInt64;
+ /** @public */
+ export const MAX = (2n ** 63n - 1n) as BigInt64;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.bigint().check(z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: bigint): input is BigInt64 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): BigInt64 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromNumber(input: number): BigInt64 {
+ return fromBigInt(BigInt(input));
+ }
+}
diff --git a/packages/types/src/numbers/BigUint128.std.ts b/packages/types/src/numbers/BigUint128.std.ts
new file mode 100644
index 0000000000..98aab6c9b7
--- /dev/null
+++ b/packages/types/src/numbers/BigUint128.std.ts
@@ -0,0 +1,38 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * Unsigned 128-bit integer
+ * @public
+ */
+export type BigUint128 = Tagged;
+
+export namespace BigUint128 {
+ /** @public */
+ export const MIN = 0n as BigUint128;
+ /** @public */
+ export const MAX = (2n ** 128n - 1n) as BigUint128;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.bigint().check(z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: bigint): input is BigUint128 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): BigUint128 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromNumber(input: number): BigUint128 {
+ return fromBigInt(BigInt(input));
+ }
+}
diff --git a/packages/types/src/numbers/BigUint64.std.ts b/packages/types/src/numbers/BigUint64.std.ts
new file mode 100644
index 0000000000..ba96d5b66b
--- /dev/null
+++ b/packages/types/src/numbers/BigUint64.std.ts
@@ -0,0 +1,38 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * Unsigned 64-bit integer
+ * @public
+ */
+export type BigUint64 = Tagged;
+
+export namespace BigUint64 {
+ /** @public */
+ export const MIN = 0n as BigUint64;
+ /** @public */
+ export const MAX = (2n ** 64n - 1n) as BigUint64;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.bigint().check(z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: bigint): input is BigUint64 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): BigUint64 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromNumber(input: number): BigUint64 {
+ return fromBigInt(BigInt(input));
+ }
+}
diff --git a/packages/types/src/numbers/Float16.std.ts b/packages/types/src/numbers/Float16.std.ts
new file mode 100644
index 0000000000..6a63392438
--- /dev/null
+++ b/packages/types/src/numbers/Float16.std.ts
@@ -0,0 +1,32 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * 16-bit IEEE 754 floating-point number.
+ * @public
+ */
+export type Float16 = Tagged;
+
+export namespace Float16 {
+ function isFloat16(input: number): boolean {
+ return Math.f16round(input) === input;
+ }
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number(),
+ z.custom(input => isFloat16(input), 'must be valid float16')
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Float16 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Float16 {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/numbers/Float32.std.ts b/packages/types/src/numbers/Float32.std.ts
new file mode 100644
index 0000000000..fc13a4e388
--- /dev/null
+++ b/packages/types/src/numbers/Float32.std.ts
@@ -0,0 +1,32 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * 32-bit IEEE 754 floating-point number.
+ * @public
+ */
+export type Float32 = Tagged;
+
+export namespace Float32 {
+ function isFloat32(input: number): boolean {
+ return Math.fround(input) === input;
+ }
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number(),
+ z.custom(input => isFloat32(input), 'must be valid float32')
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Float32 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Float32 {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/numbers/Float64.std.ts b/packages/types/src/numbers/Float64.std.ts
new file mode 100644
index 0000000000..fb871e906e
--- /dev/null
+++ b/packages/types/src/numbers/Float64.std.ts
@@ -0,0 +1,28 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+
+/**
+ * 64-bit IEEE 754 floating-point number (standard JavaScript `number`).
+ * @public
+ */
+export type Float64 = Tagged;
+
+export namespace Float64 {
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number(),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Float64 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Float64 {
+ return Schema.parse(input);
+ }
+}
diff --git a/packages/types/src/numbers/Int16.std.ts b/packages/types/src/numbers/Int16.std.ts
new file mode 100644
index 0000000000..13b584b2b6
--- /dev/null
+++ b/packages/types/src/numbers/Int16.std.ts
@@ -0,0 +1,39 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Signed 16-bit integer
+ * @public
+ */
+export type Int16 = Tagged;
+
+export namespace Int16 {
+ /** @public */
+ export const MIN = -(2 ** 15) as Int16;
+ /** @public */
+ export const MAX = (2 ** 15 - 1) as Int16;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Int16 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Int16 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): Int16 {
+ return fromNumber(bigIntToNumber(input));
+ }
+}
diff --git a/packages/types/src/numbers/Int32.std.ts b/packages/types/src/numbers/Int32.std.ts
new file mode 100644
index 0000000000..2c55f13634
--- /dev/null
+++ b/packages/types/src/numbers/Int32.std.ts
@@ -0,0 +1,39 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Signed 32-bit integer
+ * @public
+ */
+export type Int32 = Tagged;
+
+export namespace Int32 {
+ /** @public */
+ export const MIN = -(2 ** 31) as Int32;
+ /** @public */
+ export const MAX = (2 ** 31 - 1) as Int32;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Int32 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Int32 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): Int32 {
+ return fromNumber(bigIntToNumber(input));
+ }
+}
diff --git a/packages/types/src/numbers/Int8.std.ts b/packages/types/src/numbers/Int8.std.ts
new file mode 100644
index 0000000000..9c505f73ba
--- /dev/null
+++ b/packages/types/src/numbers/Int8.std.ts
@@ -0,0 +1,39 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Signed 8-bit integer
+ * @public
+ */
+export type Int8 = Tagged;
+
+export namespace Int8 {
+ /** @public */
+ export const MIN = -(2 ** 7) as Int8;
+ /** @public */
+ export const MAX = (2 ** 7 - 1) as Int8;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Int8 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Int8 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): Int8 {
+ return fromNumber(bigIntToNumber(input));
+ }
+}
diff --git a/packages/types/src/numbers/Uint16.std.ts b/packages/types/src/numbers/Uint16.std.ts
new file mode 100644
index 0000000000..ca2491b095
--- /dev/null
+++ b/packages/types/src/numbers/Uint16.std.ts
@@ -0,0 +1,39 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Unsigned 16-bit integer
+ * @public
+ */
+export type Uint16 = Tagged;
+
+export namespace Uint16 {
+ /** @public */
+ export const MIN = 0 as Uint16;
+ /** @public */
+ export const MAX = (2 ** 16 - 1) as Uint16;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Uint16 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Uint16 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): Uint16 {
+ return fromNumber(bigIntToNumber(input));
+ }
+}
diff --git a/packages/types/src/numbers/Uint32.std.ts b/packages/types/src/numbers/Uint32.std.ts
new file mode 100644
index 0000000000..58d9da0404
--- /dev/null
+++ b/packages/types/src/numbers/Uint32.std.ts
@@ -0,0 +1,39 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Unsigned 32-bit integer
+ * @public
+ */
+export type Uint32 = Tagged;
+
+export namespace Uint32 {
+ /** @public */
+ export const MIN = 0 as Uint32;
+ /** @public */
+ export const MAX = (2 ** 32 - 1) as Uint32;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom()
+ );
+
+ /** @public */
+ export function isValid(input: number): input is Uint32 {
+ return Schema.safeParse(input).success;
+ }
+
+ /** @public */
+ export function fromNumber(input: number): Uint32 {
+ return Schema.parse(input);
+ }
+
+ /** @public */
+ export function fromBigInt(input: bigint): Uint32 {
+ return fromNumber(bigIntToNumber(input));
+ }
+}
diff --git a/packages/types/src/numbers/Uint8.std.ts b/packages/types/src/numbers/Uint8.std.ts
new file mode 100644
index 0000000000..d90a812eb9
--- /dev/null
+++ b/packages/types/src/numbers/Uint8.std.ts
@@ -0,0 +1,39 @@
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+import type { Tagged } from 'type-fest';
+import * as z from 'zod/mini';
+import { bigIntToNumber } from '../_utils/numbers.std.ts';
+
+/**
+ * Unsigned 8-bit integer
+ * @public
+ */
+export type Uint8 = Tagged;
+
+export namespace Uint8 {
+ /** @public */
+ export const MIN = 0 as Uint8;
+ /** @public */
+ export const MAX = (2 ** 8 - 1) as Uint8;
+
+ /** @public */
+ export const Schema: z.ZodMiniType = z.pipe(
+ z.number().check(z.int(), z.minimum(MIN), z.maximum(MAX)),
+ z.custom