@tinycloud/web-sdk 3.11.1-beta.0 → 3.12.0-beta.2

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.
@@ -17,7 +17,7 @@ import { type BrowserProvider, type BrowserWalletProvider } from "../adapters/br
17
17
  import { type TinyCloudUI, type UiConfig } from "../ui";
18
18
  import { RPCProviders, ClientConfig } from "../providers";
19
19
  import type { NotificationConfig } from "../notifications/types";
20
- import type { PortableDelegation, DelegatedAccess } from "@tinycloud/node-sdk/core";
20
+ import type { PortableDelegation, DelegatedAccess, SpaceHosting } from "@tinycloud/node-sdk/core";
21
21
  import { CredentialsService } from "../credentials";
22
22
  import { ShareReceiverService, type ShareReceiverServiceOptions } from "../share";
23
23
  declare global {
@@ -200,6 +200,8 @@ export interface ShareReceiveResult<T = unknown> {
200
200
  export declare class TinyCloudWeb {
201
201
  private openkeySignInInFlight;
202
202
  private prepareSignInToken;
203
+ /** How long a restore waits for the node's hosting answer. */
204
+ private spaceHostingCapMs;
203
205
  private preparedSignIn?;
204
206
  private invalidatePreparedSignIn;
205
207
  /** The connected wallet's raw EIP-1193 provider. */
@@ -335,6 +337,8 @@ export declare class TinyCloudWeb {
335
337
  get delegations(): DelegationManager;
336
338
  get capabilityRegistry(): ICapabilityKeyRegistry;
337
339
  get spaceId(): string | undefined;
340
+ /** The node's last answer for whether the primary space is hosted (`"unknown"` until it has answered). */
341
+ get spaceHosting(): SpaceHosting;
338
342
  get accountSpaceId(): string | undefined;
339
343
  get account(): AccountService;
340
344
  get hosts(): string[];
@@ -383,6 +387,24 @@ export declare class TinyCloudWeb {
383
387
  private trackRestoreAddress;
384
388
  private untrackRestoreAddress;
385
389
  restoreSession(address?: string): Promise<SessionRestoreResult>;
390
+ /** One node read for the restored session, held to {@link spaceHostingCapMs}; past it, or on any failure, the answer stays unknown. */
391
+ private probeSpaceHosting;
392
+ private spaceHostingInFlight?;
393
+ /**
394
+ * Host a restored session's primary space only when the node reports it
395
+ * missing. Reuses that session and its existing creation confirmation.
396
+ * Call from a user gesture so the approval popup can open.
397
+ */
398
+ private restoredSessionNotHosted;
399
+ /**
400
+ * Ensure the primary space is hosted, asking for approval only when needed.
401
+ * Resolves `"hosted"` when the node reports hosting or the space is created;
402
+ * resolves `"not-hosted"` when creation is unavailable or declined; and
403
+ * resolves `"unknown"` when the node has no hosting answer.
404
+ * Rejects with `Error("Space hosting was cancelled by sign-out.")` if sign-out
405
+ * happens during the hosting run. Call from a user gesture so the approval popup can open.
406
+ */
407
+ ensureSpaceHosted(): Promise<SpaceHosting>;
386
408
  clearPersistedSession(address?: string): Promise<void>;
387
409
  private configuredManifestPermissions;
388
410
  /**
@@ -0,0 +1,3 @@
1
+ /** Space hosting probe and space creation, loaded when the first hosting check or creation runs. */
2
+ export { askSpaceHosting, createPrimarySpace } from "@tinycloud/node-sdk/space-hosting";
3
+ //# sourceMappingURL=space-hosting-entry.d.ts.map
@@ -0,0 +1 @@
1
+ (()=>{"use strict";var e={d:(t,a)=>{for(var s in a)e.o(a,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:a[s]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{askSpaceHosting:()=>u,createPrimarySpace:()=>w});var a=new WeakMap,s=5e3,o="tinycloud.kv/list",n="tinycloud.kv/metadata",r="tinycloud.kv/get",i="tinycloud.space/info",c=e=>""===e||e.endsWith("/")||e.endsWith("/*")||e.endsWith("/**"),d=e=>e.endsWith("/**")?e.slice(0,-2):e.endsWith("/*")?e.slice(0,-1):"/"===e?"":e,p=e=>c(e)?`${d(e)}.tinycloud-space-probe`:e;async function h(e,t){try{const{spaceId:a}=e,o=await e.fetch(`${e.host}/invoke`,{method:"POST",headers:{...e.sign([{spaceId:a,service:t.service,path:t.path,action:t.action}]),...t.headers},body:t.body,signal:AbortSignal.timeout(s)});return o.ok?(o.body instanceof ReadableStream&&await o.body.cancel().catch(()=>{}),"hosted"):401===o.status||403===o.status?"refused":404===o.status?/space not found/i.test(await o.text())?"not-hosted":"hosted":"unknown"}catch{return"unknown"}}async function u(e){const t=function({spaceId:e,operations:t,covers:a}){const s=t.filter(t=>!t.caveats?.length&&a(t,{spaceId:e,service:t.service,path:t.path,action:t.action})),h=(t,o)=>s.filter(s=>a(s,{spaceId:e,service:t,path:s.path,action:o}));return[...h("kv",o).map(e=>({service:"kv",path:c(e.path)?d(e.path):e.path,action:o,headers:{"x-tinycloud-limit":"1"}})),...h("kv",n).map(e=>({service:"kv",path:p(e.path),action:n})),...h("space",i).map(()=>({service:"space",path:"",action:i,body:"{}"})),...h("kv",r).map(e=>({service:"kv",path:p(e.path),action:r}))].find(t=>s.some(s=>a(s,{spaceId:e,service:t.service,path:t.path,action:t.action})))}(e);if(!t)return"unknown";const u=`${e.host} ${e.spaceId.replace(/^(tinycloud:pkh:eip155:\d+:)(0x[0-9a-fA-F]{40})/,(e,t,a)=>t+a.toLowerCase())}`;if(a.get(e.scope)?.has(u))return"hosted";let l=await h(e,t);if("refused"===l){try{await e.activate(AbortSignal.timeout(s))}catch{return"unknown"}l=await h(e,t)}return"hosted"===l&&a.set(e.scope,(a.get(e.scope)??new Set).add(u)),"refused"===l?"unknown":l}function l(e){const t=e.error?.trim();return t?`${e.status} - ${t}`:`${e.status}`}async function w({handler:e,session:t,context:a,currentSession:s,signerAddress:o,resolveHost:n,domain:r,hostName:i,guard:c,host:d,onHosted:p,activate:h,signal:u}){const w=()=>{if(u?.throwIfAborted(),t&&s?.()!==t)throw new Error("Space hosting session changed")};if(w(),t&&o&&(await o()).toLowerCase()!==t.address.toLowerCase())return;w();const f=a??(t&&{address:t.address,chainId:t.chainId,spaceId:t.spaceId,host:await(n?.())??i??""});if(!f)throw new Error("Space hosting requires a session context");w(),await c(f),w();const v=await e.confirmSpaceCreation(f);if(w(),!v)return;try{const e=await d(f,w,e=>({address:f.address,chainId:f.chainId,domain:r??"",issuedAt:(new Date).toISOString(),spaceId:f.spaceId,peerId:e}));if(!e.success)throw Object.assign(new Error(`Failed to create space ${f.spaceId}: ${l(e)}`),{cause:e})}catch(t){throw e.onSpaceCreationFailed?.(f,t instanceof Error?t:new Error(String(t))),t}w(),p(f),await new Promise(e=>setTimeout(e,100)),w();const y=await h(f);if(w(),!y.success){const t=Object.assign(new Error(`Failed to activate session after creating space: ${l(y)}`),{cause:y});throw e.onSpaceCreationFailed?.(f,t),t}e.onSpaceCreated?.(f)}module.exports=t})();
@@ -0,0 +1 @@
1
+ var e=new WeakMap,t="tinycloud.kv/list",a="tinycloud.kv/metadata",s="tinycloud.kv/get",n="tinycloud.space/info",o=e=>""===e||e.endsWith("/")||e.endsWith("/*")||e.endsWith("/**"),i=e=>e.endsWith("/**")?e.slice(0,-2):e.endsWith("/*")?e.slice(0,-1):"/"===e?"":e,c=e=>o(e)?`${i(e)}.tinycloud-space-probe`:e;async function r(e,t){try{const{spaceId:a}=e,s=await e.fetch(`${e.host}/invoke`,{method:"POST",headers:{...e.sign([{spaceId:a,service:t.service,path:t.path,action:t.action}]),...t.headers},body:t.body,signal:AbortSignal.timeout(5e3)});return s.ok?(s.body instanceof ReadableStream&&await s.body.cancel().catch(()=>{}),"hosted"):401===s.status||403===s.status?"refused":404===s.status?/space not found/i.test(await s.text())?"not-hosted":"hosted":"unknown"}catch{return"unknown"}}async function d(d){const h=function({spaceId:e,operations:r,covers:d}){const h=r.filter(t=>!t.caveats?.length&&d(t,{spaceId:e,service:t.service,path:t.path,action:t.action})),p=(t,a)=>h.filter(s=>d(s,{spaceId:e,service:t,path:s.path,action:a}));return[...p("kv",t).map(e=>({service:"kv",path:o(e.path)?i(e.path):e.path,action:t,headers:{"x-tinycloud-limit":"1"}})),...p("kv",a).map(e=>({service:"kv",path:c(e.path),action:a})),...p("space",n).map(()=>({service:"space",path:"",action:n,body:"{}"})),...p("kv",s).map(e=>({service:"kv",path:c(e.path),action:s}))].find(t=>h.some(a=>d(a,{spaceId:e,service:t.service,path:t.path,action:t.action})))}(d);if(!h)return"unknown";const p=`${d.host} ${d.spaceId.replace(/^(tinycloud:pkh:eip155:\d+:)(0x[0-9a-fA-F]{40})/,(e,t,a)=>t+a.toLowerCase())}`;if(e.get(d.scope)?.has(p))return"hosted";let u=await r(d,h);if("refused"===u){try{await d.activate(AbortSignal.timeout(5e3))}catch{return"unknown"}u=await r(d,h)}return"hosted"===u&&e.set(d.scope,(e.get(d.scope)??new Set).add(p)),"refused"===u?"unknown":u}function h(e){const t=e.error?.trim();return t?`${e.status} - ${t}`:`${e.status}`}async function p({handler:e,session:t,context:a,currentSession:s,signerAddress:n,resolveHost:o,domain:i,hostName:c,guard:r,host:d,onHosted:p,activate:u,signal:w}){const f=()=>{if(w?.throwIfAborted(),t&&s?.()!==t)throw new Error("Space hosting session changed")};if(f(),t&&n&&(await n()).toLowerCase()!==t.address.toLowerCase())return;f();const l=a??(t&&{address:t.address,chainId:t.chainId,spaceId:t.spaceId,host:await(o?.())??c??""});if(!l)throw new Error("Space hosting requires a session context");f(),await r(l),f();const v=await e.confirmSpaceCreation(l);if(f(),!v)return;try{const e=await d(l,f,e=>({address:l.address,chainId:l.chainId,domain:i??"",issuedAt:(new Date).toISOString(),spaceId:l.spaceId,peerId:e}));if(!e.success)throw Object.assign(new Error(`Failed to create space ${l.spaceId}: ${h(e)}`),{cause:e})}catch(t){throw e.onSpaceCreationFailed?.(l,t instanceof Error?t:new Error(String(t))),t}f(),p(l),await new Promise(e=>setTimeout(e,100)),f();const g=await u(l);if(f(),!g.success){const t=Object.assign(new Error(`Failed to activate session after creating space: ${h(g)}`),{cause:g});throw e.onSpaceCreationFailed?.(l,t),t}e.onSpaceCreated?.(l)}export{d as askSpaceHosting,p as createPrimarySpace};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinycloud/web-sdk",
3
- "version": "3.11.1-beta.0",
3
+ "version": "3.12.0-beta.2",
4
4
  "description": "A set of tools and utilities to help you build your app with TinyCloud.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -66,7 +66,7 @@
66
66
  "@multiformats/multiaddr": "^13.0.1",
67
67
  "@multiformats/multiaddr-to-uri": "^12.0.0",
68
68
  "@noble/curves": "^1.9.7",
69
- "@tinycloud/node-sdk": "3.11.1-beta.0",
69
+ "@tinycloud/node-sdk": "3.12.0-beta.2",
70
70
  "@tinycloud/replica": "0.4.4",
71
71
  "@tinycloud/sdk-core": "3.11.0",
72
72
  "@tinycloud/share-envelope": "1.5.0",