@unicitylabs/sphere-sdk 0.17.2-dev.3 → 0.17.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,6 +38,7 @@ __export(core_exports, {
38
38
  FIELD_ENVELOPE_MAX_BYTES: () => FIELD_ENVELOPE_MAX_BYTES,
39
39
  FIELD_ENVELOPE_NONCE_BYTES: () => FIELD_ENVELOPE_NONCE_BYTES,
40
40
  FIELD_ENVELOPE_PREFIX: () => FIELD_ENVELOPE_PREFIX,
41
+ NO_PAYMENTS: () => NO_PAYMENTS,
41
42
  PartialSendConflictError: () => PartialSendConflictError,
42
43
  SIGN_MESSAGE_PREFIX: () => SIGN_MESSAGE_PREFIX,
43
44
  Sphere: () => Sphere,
@@ -4624,6 +4625,26 @@ var GroupVisibility = {
4624
4625
  PRIVATE: "PRIVATE"
4625
4626
  };
4626
4627
 
4628
+ // modules/groupchat/group-id.ts
4629
+ var MAX_SLUG_LENGTH = 24;
4630
+ var RANDOM_BYTES = 8;
4631
+ function groupIdSlug(name) {
4632
+ const slug = name.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/['\u2019]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4633
+ if (slug.length <= MAX_SLUG_LENGTH) return slug;
4634
+ const head = slug.slice(0, MAX_SLUG_LENGTH + 1);
4635
+ const hyphen = head.lastIndexOf("-");
4636
+ return hyphen > 0 ? head.slice(0, hyphen) : slug.slice(0, MAX_SLUG_LENGTH);
4637
+ }
4638
+ function newGroupId(name) {
4639
+ const crypto2 = globalThis.crypto;
4640
+ if (typeof crypto2?.getRandomValues !== "function") {
4641
+ throw new SphereError("Creating a group requires crypto.getRandomValues", "INVALID_CONFIG");
4642
+ }
4643
+ const bytes = crypto2.getRandomValues(new Uint8Array(RANDOM_BYTES));
4644
+ const random = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4645
+ return `${groupIdSlug(name) || "group"}-${random}`;
4646
+ }
4647
+
4627
4648
  // modules/groupchat/GroupChatModule.ts
4628
4649
  function createNip29Filter(data) {
4629
4650
  return new import_nostr_js_sdk3.Filter(data);
@@ -5235,9 +5256,9 @@ var GroupChatModule = class {
5235
5256
  if (!this.client) return null;
5236
5257
  const creatorPubkey = this.getMyPublicKey();
5237
5258
  if (!creatorPubkey) return null;
5238
- const proposedGroupId = options.name.toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 20) || this.randomId();
5239
5259
  try {
5240
5260
  const isPrivate = options.visibility === GroupVisibility.PRIVATE;
5261
+ const proposedGroupId = newGroupId(options.name);
5241
5262
  const eventId = await this.client.createAndPublishEvent({
5242
5263
  kind: NIP29_KINDS.CREATE_GROUP,
5243
5264
  tags: [["h", proposedGroupId]],
@@ -17041,7 +17062,16 @@ var WalletApiSplitCheckpointStore = class {
17041
17062
  };
17042
17063
 
17043
17064
  // core/payments-v2-wiring.ts
17065
+ var NO_PAYMENTS = "none";
17066
+ function readPaymentsOptOut(walletApi) {
17067
+ if (walletApi === NO_PAYMENTS) return NO_PAYMENTS;
17068
+ throw new SphereError(
17069
+ `walletApi must be a wallet-api transport config or the literal '${NO_PAYMENTS}' (the explicit messaging-only opt-out, #793) \u2014 received ${JSON.stringify(walletApi)}.`,
17070
+ "INVALID_CONFIG"
17071
+ );
17072
+ }
17044
17073
  function resolvePaymentsV2Composition(walletApi, sphereNetwork) {
17074
+ if (typeof walletApi === "string") return readPaymentsOptOut(walletApi);
17045
17075
  const source = walletApi;
17046
17076
  const network = typeof source?.network === "string" && source.network !== "" ? source.network : null;
17047
17077
  if (!source || network === null) {
@@ -17321,7 +17351,11 @@ var Sphere = class _Sphere {
17321
17351
  // The payments vertical (the ONLY money path since the P11 flip)
17322
17352
  /** The ACTIVE address's running vertical — §7: exactly one at a time, ever. */
17323
17353
  _paymentsV2Active = null;
17324
- /** Resolved wallet-api transport composition (network + per-address factory); set at init, fail-closed. */
17354
+ /**
17355
+ * Money composition, set at init. `null` = never resolved (a construction bug),
17356
+ * `NO_PAYMENTS` = the explicit #793 opt-out, an object = a real composition. One
17357
+ * spelling for the last two would read a forgotten resolve as messaging-only.
17358
+ */
17325
17359
  _paymentsV2Composition = null;
17326
17360
  /**
17327
17361
  * §7 lifecycle mutex: every stop/start pair runs strictly serialized, so
@@ -17997,10 +18031,24 @@ var Sphere = class _Sphere {
17997
18031
  get payments() {
17998
18032
  const facade = this._paymentsV2Active?.facade;
17999
18033
  if (!facade) {
18034
+ if (this._paymentsV2Composition === NO_PAYMENTS) {
18035
+ throw new SphereError(
18036
+ "payments is not composed: this Sphere was initialised with `walletApi: 'none'`, the explicit messaging-only composition. Money has no path here \u2014 re-init with a wallet-api transport config to move any.",
18037
+ "PAYMENTS_NOT_COMPOSED"
18038
+ );
18039
+ }
18000
18040
  throw new SphereError("Sphere not initialized", "NOT_INITIALIZED");
18001
18041
  }
18002
18042
  return facade;
18003
18043
  }
18044
+ /**
18045
+ * Whether this Sphere composes money at all (#793) — fixed for the instance's life,
18046
+ * so a messaging-only wallet can branch without a try/catch. Not a liveness check:
18047
+ * `true` still leaves `payments` throwing NOT_INITIALIZED mid-init or mid-switch.
18048
+ */
18049
+ get hasPayments() {
18050
+ return this._paymentsV2Composition !== NO_PAYMENTS;
18051
+ }
18004
18052
  /** Communications module */
18005
18053
  get communications() {
18006
18054
  this.ensureReady();
@@ -20028,6 +20076,7 @@ var Sphere = class _Sphere {
20028
20076
  * breaks initialization.
20029
20077
  */
20030
20078
  async buildTokenEngine(identity) {
20079
+ if (this._paymentsV2Composition === NO_PAYMENTS) return void 0;
20031
20080
  const oracle = this._oracle;
20032
20081
  const privateKey = (identity ?? this._identity)?.privateKey;
20033
20082
  const trustBaseJson = oracle.getTrustBaseJson?.() ?? null;
@@ -20133,6 +20182,7 @@ var Sphere = class _Sphere {
20133
20182
  * setOracleApiKey rebuild is what future operations snapshot.
20134
20183
  */
20135
20184
  async startPaymentsV2Inner(index, identity) {
20185
+ if (this._paymentsV2Composition === NO_PAYMENTS) return;
20136
20186
  if (!this._paymentsV2Composition) {
20137
20187
  throw new SphereError("wallet-api composition required for money", "INVALID_CONFIG");
20138
20188
  }
@@ -20513,6 +20563,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
20513
20563
  FIELD_ENVELOPE_MAX_BYTES,
20514
20564
  FIELD_ENVELOPE_NONCE_BYTES,
20515
20565
  FIELD_ENVELOPE_PREFIX,
20566
+ NO_PAYMENTS,
20516
20567
  PartialSendConflictError,
20517
20568
  SIGN_MESSAGE_PREFIX,
20518
20569
  Sphere,