voidnote 0.2.0__tar.gz → 0.3.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voidnote
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Official SDK for VoidNote — zero-knowledge self-destructing notes and live encrypted streams
5
5
  Project-URL: Homepage, https://voidnote.net
6
6
  Project-URL: Repository, https://github.com/quantum-encoding/voidnote-python
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "voidnote"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Official SDK for VoidNote — zero-knowledge self-destructing notes and live encrypted streams"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -113,17 +113,21 @@ def create(
113
113
  api_key: str,
114
114
  title: Optional[str] = None,
115
115
  max_views: int = 1,
116
+ expires_in: int = 24,
117
+ note_type: Literal["secure", "pipe"] = "secure",
116
118
  base: str = DEFAULT_BASE,
117
119
  ) -> CreateResult:
118
120
  """
119
121
  Create a VoidNote. Encrypts content client-side — the server never sees plaintext.
120
122
 
121
123
  Args:
122
- content: The secret text to encrypt and store
123
- api_key: Your API key from dashboard (vn_...)
124
- title: Optional plaintext title (keep non-sensitive)
125
- max_views: How many times the note can be read (1–100)
126
- base: Override base URL (default: https://voidnote.net)
124
+ content: The secret text to encrypt and store
125
+ api_key: Your API key from dashboard (vn_...)
126
+ title: Optional plaintext title (keep non-sensitive)
127
+ max_views: How many times the note can be read (1–100)
128
+ expires_in: Lifetime in hours — one of: 1, 6, 24, 72, 168, 720
129
+ note_type: "secure" (default) or "pipe"
130
+ base: Override base URL (default: https://voidnote.net)
127
131
 
128
132
  Returns:
129
133
  CreateResult with .url (shareable link) and .expires_at
@@ -134,6 +138,8 @@ def create(
134
138
  """
135
139
  if not 1 <= max_views <= 100:
136
140
  raise ValueError("max_views must be between 1 and 100")
141
+ if expires_in not in (1, 6, 24, 72, 168, 720):
142
+ raise ValueError("expires_in must be one of: 1, 6, 24, 72, 168, 720")
137
143
 
138
144
  full_token, token_id, secret = _generate_token()
139
145
  encrypted_content, iv = _encrypt(content, secret)
@@ -143,6 +149,8 @@ def create(
143
149
  "encryptedContent": encrypted_content,
144
150
  "iv": iv,
145
151
  "maxViews": max_views,
152
+ "expiresIn": expires_in,
153
+ "noteType": note_type,
146
154
  }
147
155
  if title:
148
156
  payload["title"] = title
@@ -351,7 +359,103 @@ def _decrypt_stream_msg(enc_hex: str, iv_hex: str, key: bytes) -> str:
351
359
  return plaintext.decode("utf-8")
352
360
 
353
361
 
362
+ # ---------------------------------------------------------------------------
363
+ # Buy / Credits API
364
+ # ---------------------------------------------------------------------------
365
+
366
+ @dataclass
367
+ class CryptoOrder:
368
+ order_id: str
369
+ to_address: str
370
+ chain: str
371
+ token: str
372
+ amount: str # human-readable, e.g. "5.000000"
373
+ amount_usd: float
374
+ credits: int
375
+ expires_at: str
376
+
377
+
378
+ @dataclass
379
+ class SubmitPaymentResult:
380
+ credits: int
381
+ credits_added: int
382
+
383
+
384
+ def create_crypto_order(
385
+ *,
386
+ api_key: str,
387
+ bundle_id: Literal["test", "starter", "standard", "pro"],
388
+ chain: Literal["polygon", "base", "arbitrum", "ethereum", "bitcoin", "tron"],
389
+ token: Literal["USDT", "USDC", "ETH", "BTC", "TRX"],
390
+ base: str = DEFAULT_BASE,
391
+ ) -> CryptoOrder:
392
+ """
393
+ Create a crypto payment order for credits.
394
+ Returns an address and exact amount to send — valid for 1 hour.
395
+
396
+ Args:
397
+ api_key: Your API key (vn_...) from the dashboard
398
+ bundle_id: "test" ($1/20), "starter" ($5/100), "standard" ($20/500), "pro" ($35/1000)
399
+ chain: Payment network
400
+ token: Token to send
401
+ base: Override base URL
402
+
403
+ Example:
404
+ order = voidnote.create_crypto_order(
405
+ api_key="vn_...", bundle_id="starter", chain="polygon", token="USDT"
406
+ )
407
+ print(f"Send {order.amount} {order.token} to {order.to_address}")
408
+ """
409
+ body = json.dumps({"bundleId": bundle_id, "chain": chain, "token": token}).encode()
410
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
411
+ data, status = _fetch(f"{base}/api/buy/crypto/create-order", method="POST", headers=headers, body=body)
412
+ if status >= 400:
413
+ raise RuntimeError(data.get("error", f"HTTP {status}"))
414
+ return CryptoOrder(
415
+ order_id=data["orderId"],
416
+ to_address=data["toAddress"],
417
+ chain=data["chain"],
418
+ token=data["token"],
419
+ amount=data["amount"],
420
+ amount_usd=data["amountUsd"],
421
+ credits=data["credits"],
422
+ expires_at=data["expiresAt"],
423
+ )
424
+
425
+
426
+ def submit_crypto_payment(
427
+ *,
428
+ api_key: str,
429
+ order_id: str,
430
+ tx_hash: str,
431
+ base: str = DEFAULT_BASE,
432
+ ) -> SubmitPaymentResult:
433
+ """
434
+ Submit a transaction hash to confirm a crypto payment.
435
+ Verifies on-chain and credits your account instantly.
436
+
437
+ Args:
438
+ api_key: Your API key (vn_...) from the dashboard
439
+ order_id: Order ID from create_crypto_order()
440
+ tx_hash: Transaction hash from your wallet
441
+ base: Override base URL
442
+
443
+ Example:
444
+ result = voidnote.submit_crypto_payment(
445
+ api_key="vn_...", order_id=order.order_id, tx_hash="0x..."
446
+ )
447
+ print(f"New balance: {result.credits} credits")
448
+ """
449
+ body = json.dumps({"orderId": order_id, "txHash": tx_hash}).encode()
450
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
451
+ data, status = _fetch(f"{base}/api/buy/crypto/submit-tx", method="POST", headers=headers, body=body)
452
+ if status >= 400:
453
+ raise RuntimeError(data.get("error", f"HTTP {status}"))
454
+ return SubmitPaymentResult(credits=data["credits"], credits_added=data["creditsAdded"])
455
+
456
+
354
457
  __all__ = [
355
458
  "read", "create", "ReadResult", "CreateResult",
356
459
  "create_stream", "watch", "StreamHandle",
460
+ "CryptoOrder", "SubmitPaymentResult", "create_crypto_order", "submit_crypto_payment",
357
461
  ]
File without changes