@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.
package/dist/index.cjs CHANGED
@@ -58,6 +58,7 @@ __export(index_exports, {
58
58
  NFT_SIGNED_TAG: () => NFT_SIGNED_TAG,
59
59
  NIP29_KINDS: () => NIP29_KINDS,
60
60
  NOSTR_EVENT_KINDS: () => NOSTR_EVENT_KINDS,
61
+ NO_PAYMENTS: () => NO_PAYMENTS,
61
62
  NostrClient: () => import_nostr_js_sdk6.NostrClient,
62
63
  NostrKeyManager: () => import_nostr_js_sdk6.NostrKeyManager,
63
64
  PartialSendConflictError: () => PartialSendConflictError,
@@ -4696,6 +4697,26 @@ var GroupVisibility = {
4696
4697
  PRIVATE: "PRIVATE"
4697
4698
  };
4698
4699
 
4700
+ // modules/groupchat/group-id.ts
4701
+ var MAX_SLUG_LENGTH = 24;
4702
+ var RANDOM_BYTES = 8;
4703
+ function groupIdSlug(name) {
4704
+ const slug = name.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/['\u2019]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4705
+ if (slug.length <= MAX_SLUG_LENGTH) return slug;
4706
+ const head = slug.slice(0, MAX_SLUG_LENGTH + 1);
4707
+ const hyphen = head.lastIndexOf("-");
4708
+ return hyphen > 0 ? head.slice(0, hyphen) : slug.slice(0, MAX_SLUG_LENGTH);
4709
+ }
4710
+ function newGroupId(name) {
4711
+ const crypto2 = globalThis.crypto;
4712
+ if (typeof crypto2?.getRandomValues !== "function") {
4713
+ throw new SphereError("Creating a group requires crypto.getRandomValues", "INVALID_CONFIG");
4714
+ }
4715
+ const bytes = crypto2.getRandomValues(new Uint8Array(RANDOM_BYTES));
4716
+ const random = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4717
+ return `${groupIdSlug(name) || "group"}-${random}`;
4718
+ }
4719
+
4699
4720
  // modules/groupchat/GroupChatModule.ts
4700
4721
  function createNip29Filter(data) {
4701
4722
  return new import_nostr_js_sdk3.Filter(data);
@@ -5307,9 +5328,9 @@ var GroupChatModule = class {
5307
5328
  if (!this.client) return null;
5308
5329
  const creatorPubkey = this.getMyPublicKey();
5309
5330
  if (!creatorPubkey) return null;
5310
- const proposedGroupId = options.name.toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 20) || this.randomId();
5311
5331
  try {
5312
5332
  const isPrivate = options.visibility === GroupVisibility.PRIVATE;
5333
+ const proposedGroupId = newGroupId(options.name);
5313
5334
  const eventId = await this.client.createAndPublishEvent({
5314
5335
  kind: NIP29_KINDS.CREATE_GROUP,
5315
5336
  tags: [["h", proposedGroupId]],
@@ -17128,7 +17149,16 @@ var WalletApiSplitCheckpointStore = class {
17128
17149
  };
17129
17150
 
17130
17151
  // core/payments-v2-wiring.ts
17152
+ var NO_PAYMENTS = "none";
17153
+ function readPaymentsOptOut(walletApi) {
17154
+ if (walletApi === NO_PAYMENTS) return NO_PAYMENTS;
17155
+ throw new SphereError(
17156
+ `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)}.`,
17157
+ "INVALID_CONFIG"
17158
+ );
17159
+ }
17131
17160
  function resolvePaymentsV2Composition(walletApi, sphereNetwork) {
17161
+ if (typeof walletApi === "string") return readPaymentsOptOut(walletApi);
17132
17162
  const source = walletApi;
17133
17163
  const network = typeof source?.network === "string" && source.network !== "" ? source.network : null;
17134
17164
  if (!source || network === null) {
@@ -17408,7 +17438,11 @@ var Sphere = class _Sphere {
17408
17438
  // The payments vertical (the ONLY money path since the P11 flip)
17409
17439
  /** The ACTIVE address's running vertical — §7: exactly one at a time, ever. */
17410
17440
  _paymentsV2Active = null;
17411
- /** Resolved wallet-api transport composition (network + per-address factory); set at init, fail-closed. */
17441
+ /**
17442
+ * Money composition, set at init. `null` = never resolved (a construction bug),
17443
+ * `NO_PAYMENTS` = the explicit #793 opt-out, an object = a real composition. One
17444
+ * spelling for the last two would read a forgotten resolve as messaging-only.
17445
+ */
17412
17446
  _paymentsV2Composition = null;
17413
17447
  /**
17414
17448
  * §7 lifecycle mutex: every stop/start pair runs strictly serialized, so
@@ -18084,10 +18118,24 @@ var Sphere = class _Sphere {
18084
18118
  get payments() {
18085
18119
  const facade = this._paymentsV2Active?.facade;
18086
18120
  if (!facade) {
18121
+ if (this._paymentsV2Composition === NO_PAYMENTS) {
18122
+ throw new SphereError(
18123
+ "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.",
18124
+ "PAYMENTS_NOT_COMPOSED"
18125
+ );
18126
+ }
18087
18127
  throw new SphereError("Sphere not initialized", "NOT_INITIALIZED");
18088
18128
  }
18089
18129
  return facade;
18090
18130
  }
18131
+ /**
18132
+ * Whether this Sphere composes money at all (#793) — fixed for the instance's life,
18133
+ * so a messaging-only wallet can branch without a try/catch. Not a liveness check:
18134
+ * `true` still leaves `payments` throwing NOT_INITIALIZED mid-init or mid-switch.
18135
+ */
18136
+ get hasPayments() {
18137
+ return this._paymentsV2Composition !== NO_PAYMENTS;
18138
+ }
18091
18139
  /** Communications module */
18092
18140
  get communications() {
18093
18141
  this.ensureReady();
@@ -20115,6 +20163,7 @@ var Sphere = class _Sphere {
20115
20163
  * breaks initialization.
20116
20164
  */
20117
20165
  async buildTokenEngine(identity) {
20166
+ if (this._paymentsV2Composition === NO_PAYMENTS) return void 0;
20118
20167
  const oracle = this._oracle;
20119
20168
  const privateKey = (identity ?? this._identity)?.privateKey;
20120
20169
  const trustBaseJson = oracle.getTrustBaseJson?.() ?? null;
@@ -20220,6 +20269,7 @@ var Sphere = class _Sphere {
20220
20269
  * setOracleApiKey rebuild is what future operations snapshot.
20221
20270
  */
20222
20271
  async startPaymentsV2Inner(index, identity) {
20272
+ if (this._paymentsV2Composition === NO_PAYMENTS) return;
20223
20273
  if (!this._paymentsV2Composition) {
20224
20274
  throw new SphereError("wallet-api composition required for money", "INVALID_CONFIG");
20225
20275
  }
@@ -20904,6 +20954,7 @@ function addressesMatch(a, b) {
20904
20954
  NFT_SIGNED_TAG,
20905
20955
  NIP29_KINDS,
20906
20956
  NOSTR_EVENT_KINDS,
20957
+ NO_PAYMENTS,
20907
20958
  NostrClient,
20908
20959
  NostrKeyManager,
20909
20960
  PartialSendConflictError,