@astrale-os/shell-react 0.2.5 → 0.2.6

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.d.ts CHANGED
@@ -26,8 +26,8 @@ export { SelectionScope, useSelection } from './selection/index.js';
26
26
  export type { Selection, SelectionScopeProps } from './selection/index.js';
27
27
  export { useCloseGuard, useTargetNode, useViewsFor, useWindow, useWindowList, useWindows, ViewHost, ViewStage, } from './window/index.js';
28
28
  export type { CloseGuard, CloseVerdict, ViewDescriptor, ViewHostProps, ViewSource, ViewHostHandle, ViewsForResult, WindowListEntry, WindowState, WindowView, } from './window/index.js';
29
- export { useIntent, useSendIntent } from './intents/index.js';
30
- export type { IntentCtx, IntentPayload, IntentReply, SendIntent } from './intents/index.js';
29
+ export { useEmitIntent, useIntent, useSendIntent } from './intents/index.js';
30
+ export type { EmitIntent, IntentCtx, IntentPayload, IntentReply, SendIntent, } from './intents/index.js';
31
31
  export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useSpace, useSpaces, useUser, } from './application/index.js';
32
32
  export type { AppHostFallbackState, AppHostProps, AppLogoProps, AppsResult, CurrentSpaceResult, RolesResult, SpaceResult, SpacesResult, } from './application/index.js';
33
33
  export type { ApplicationNode, AppSession, RoleNode, SpaceNode, UserNode } from '@astrale-os/shell';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ export { SelectionScope, useSelection } from './selection/index.js';
25
25
  // ─── window (§10) ────────────────────────────────────────────────────────────
26
26
  export { useCloseGuard, useTargetNode, useViewsFor, useWindow, useWindowList, useWindows, ViewHost, ViewStage, } from './window/index.js';
27
27
  // ─── intents (§11) ───────────────────────────────────────────────────────────
28
- export { useIntent, useSendIntent } from './intents/index.js';
28
+ export { useEmitIntent, useIntent, useSendIntent } from './intents/index.js';
29
29
  // ─── application — the OS plane (§12) ────────────────────────────────────────
30
30
  export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useSpace, useSpaces, useUser, } from './application/index.js';
31
31
  // ─── error taxonomy (§1.4) — guards + classes, re-exported from kernel-client ─
@@ -0,0 +1,17 @@
1
+ import type { IntentRegistry } from '@astrale-os/shell';
2
+ import type { IntentPayload } from './envelope.js';
3
+ /** Fire-and-forget intent sender returned by {@link useEmitIntent}. */
4
+ export interface EmitIntent {
5
+ <K extends keyof IntentRegistry>(name: K, payload: IntentPayload<K>,
6
+ /** `to`: `'parent'` (reserved) or a child windowId. Default: the parent, if any. */
7
+ opts?: {
8
+ to?: 'parent' | string;
9
+ }): void;
10
+ }
11
+ /**
12
+ * Return a stable sender for intents that do not need a reply. Emitted messages
13
+ * carry no correlation id, so listeners can handle navigation and notifications
14
+ * without retaining a pending request.
15
+ */
16
+ export declare function useEmitIntent(): EmitIntent;
17
+ //# sourceMappingURL=emit-intent.hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-intent.hook.d.ts","sourceRoot":"","sources":["../../src/intents/emit-intent.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAMlD,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7B,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACzB,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;KAAE,GAChC,IAAI,CAAA;CACR;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAgB1C"}
@@ -0,0 +1,22 @@
1
+ import { useCallback } from 'react';
2
+ import { useShell } from '../session/shell.hook.js';
3
+ import { intentMessage } from './envelope.js';
4
+ import { resolveIntentTarget } from './resolve-intent-target.js';
5
+ /**
6
+ * Return a stable sender for intents that do not need a reply. Emitted messages
7
+ * carry no correlation id, so listeners can handle navigation and notifications
8
+ * without retaining a pending request.
9
+ */
10
+ export function useEmitIntent() {
11
+ const shell = useShell();
12
+ return useCallback((name, payload, opts) => {
13
+ const target = resolveIntentTarget(shell, opts?.to);
14
+ if (target.kind === 'invalid')
15
+ throw new Error(`useEmitIntent: ${target.reason}`);
16
+ const message = intentMessage(name, payload);
17
+ if (target.kind === 'parent')
18
+ shell.parent.send(message);
19
+ else
20
+ shell.children.send(target.windowId, message);
21
+ }, [shell]);
22
+ }
@@ -1,5 +1,7 @@
1
1
  export { useIntent } from './listen-intent.hook.js';
2
2
  export type { IntentCtx } from './listen-intent.hook.js';
3
+ export { useEmitIntent } from './emit-intent.hook.js';
4
+ export type { EmitIntent } from './emit-intent.hook.js';
3
5
  export { useSendIntent } from './send-intent.hook.js';
4
6
  export type { SendIntent } from './send-intent.hook.js';
5
7
  export type { IntentPayload, IntentReply } from './envelope.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/intents/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/intents/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
@@ -1,3 +1,4 @@
1
1
  // intents — API §11 (useIntent, useSendIntent). See SHELL_REACT_API.md.
2
2
  export { useIntent } from './listen-intent.hook.js';
3
+ export { useEmitIntent } from './emit-intent.hook.js';
3
4
  export { useSendIntent } from './send-intent.hook.js';
@@ -0,0 +1,12 @@
1
+ import type { Shell } from '@astrale-os/shell';
2
+ export type IntentTarget = {
3
+ readonly kind: 'parent';
4
+ } | {
5
+ readonly kind: 'child';
6
+ readonly windowId: string;
7
+ } | {
8
+ readonly kind: 'invalid';
9
+ readonly reason: string;
10
+ };
11
+ export declare function resolveIntentTarget(shell: Shell, to: string | undefined): IntentTarget;
12
+ //# sourceMappingURL=resolve-intent-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-intent-target.d.ts","sourceRoot":"","sources":["../../src/intents/resolve-intent-target.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAYtF"}
@@ -0,0 +1,13 @@
1
+ export function resolveIntentTarget(shell, to) {
2
+ if (to === undefined) {
3
+ return shell.parent !== null
4
+ ? { kind: 'parent' }
5
+ : { kind: 'invalid', reason: 'no target — pass opts.to (a child windowId) from a root shell' };
6
+ }
7
+ if (to === 'parent') {
8
+ return shell.parent !== null
9
+ ? { kind: 'parent' }
10
+ : { kind: 'invalid', reason: "opts.to 'parent' but this shell has no parent channel" };
11
+ }
12
+ return { kind: 'child', windowId: to };
13
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"send-intent.hook.d.ts","sourceRoot":"","sources":["../../src/intents/send-intent.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAS,MAAM,mBAAmB,CAAA;AAW7E,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK/D,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7B,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACzB,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;KAAE,GAChC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;CAClC;AAqBD,wBAAgB,aAAa,IAAI,UAAU,CAiE1C"}
1
+ {"version":3,"file":"send-intent.hook.d.ts","sourceRoot":"","sources":["../../src/intents/send-intent.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAWtE,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAM/D,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7B,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACzB,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;KAAE,GAChC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;CAClC;AAED,wBAAgB,aAAa,IAAI,UAAU,CAiE1C"}
@@ -8,19 +8,7 @@
8
8
  import { useCallback, useEffect, useRef } from 'react';
9
9
  import { useShell } from '../session/shell.hook.js';
10
10
  import { INTENT_REPLY, NOOP, intentMessage } from './envelope.js';
11
- function resolveTarget(shell, to) {
12
- if (to === undefined) {
13
- return shell.parent !== null
14
- ? { kind: 'parent' }
15
- : { kind: 'invalid', reason: 'no target — pass opts.to (a child windowId) from a root shell' };
16
- }
17
- if (to === 'parent') {
18
- return shell.parent !== null
19
- ? { kind: 'parent' }
20
- : { kind: 'invalid', reason: "opts.to 'parent' but this shell has no parent channel" };
21
- }
22
- return { kind: 'child', windowId: to };
23
- }
11
+ import { resolveIntentTarget } from './resolve-intent-target.js';
24
12
  export function useSendIntent() {
25
13
  const shell = useShell();
26
14
  // Unmount settlers for in-flight sends, so a pending reply resolves on teardown.
@@ -34,7 +22,7 @@ export function useSendIntent() {
34
22
  };
35
23
  }, []);
36
24
  return useCallback((name, payload, opts) => {
37
- const target = resolveTarget(shell, opts?.to);
25
+ const target = resolveIntentTarget(shell, opts?.to);
38
26
  if (target.kind === 'invalid') {
39
27
  return Promise.reject(new Error(`useSendIntent: ${target.reason}`));
40
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/shell-react",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Astrale shell-react — the React face of the shell (provider, hooks, view components)",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/index.ts CHANGED
@@ -117,8 +117,14 @@ export type {
117
117
  } from './window/index.js'
118
118
 
119
119
  // ─── intents (§11) ───────────────────────────────────────────────────────────
120
- export { useIntent, useSendIntent } from './intents/index.js'
121
- export type { IntentCtx, IntentPayload, IntentReply, SendIntent } from './intents/index.js'
120
+ export { useEmitIntent, useIntent, useSendIntent } from './intents/index.js'
121
+ export type {
122
+ EmitIntent,
123
+ IntentCtx,
124
+ IntentPayload,
125
+ IntentReply,
126
+ SendIntent,
127
+ } from './intents/index.js'
122
128
 
123
129
  // ─── application — the OS plane (§12) ────────────────────────────────────────
124
130
  export {
@@ -0,0 +1,42 @@
1
+ import type { IntentRegistry } from '@astrale-os/shell'
2
+
3
+ import { useCallback } from 'react'
4
+
5
+ import type { IntentPayload } from './envelope.js'
6
+
7
+ import { useShell } from '../session/shell.hook.js'
8
+ import { intentMessage } from './envelope.js'
9
+ import { resolveIntentTarget } from './resolve-intent-target.js'
10
+
11
+ /** Fire-and-forget intent sender returned by {@link useEmitIntent}. */
12
+ export interface EmitIntent {
13
+ <K extends keyof IntentRegistry>(
14
+ name: K,
15
+ payload: IntentPayload<K>,
16
+ /** `to`: `'parent'` (reserved) or a child windowId. Default: the parent, if any. */
17
+ opts?: { to?: 'parent' | string },
18
+ ): void
19
+ }
20
+
21
+ /**
22
+ * Return a stable sender for intents that do not need a reply. Emitted messages
23
+ * carry no correlation id, so listeners can handle navigation and notifications
24
+ * without retaining a pending request.
25
+ */
26
+ export function useEmitIntent(): EmitIntent {
27
+ const shell = useShell()
28
+ return useCallback(
29
+ <K extends keyof IntentRegistry>(
30
+ name: K,
31
+ payload: IntentPayload<K>,
32
+ opts?: { to?: 'parent' | string },
33
+ ): void => {
34
+ const target = resolveIntentTarget(shell, opts?.to)
35
+ if (target.kind === 'invalid') throw new Error(`useEmitIntent: ${target.reason}`)
36
+ const message = intentMessage(name, payload)
37
+ if (target.kind === 'parent') shell.parent!.send(message)
38
+ else shell.children.send(target.windowId, message)
39
+ },
40
+ [shell],
41
+ )
42
+ }
@@ -1,6 +1,8 @@
1
1
  // intents — API §11 (useIntent, useSendIntent). See SHELL_REACT_API.md.
2
2
  export { useIntent } from './listen-intent.hook.js'
3
3
  export type { IntentCtx } from './listen-intent.hook.js'
4
+ export { useEmitIntent } from './emit-intent.hook.js'
5
+ export type { EmitIntent } from './emit-intent.hook.js'
4
6
  export { useSendIntent } from './send-intent.hook.js'
5
7
  export type { SendIntent } from './send-intent.hook.js'
6
8
  export type { IntentPayload, IntentReply } from './envelope.js'
@@ -0,0 +1,20 @@
1
+ import type { Shell } from '@astrale-os/shell'
2
+
3
+ export type IntentTarget =
4
+ | { readonly kind: 'parent' }
5
+ | { readonly kind: 'child'; readonly windowId: string }
6
+ | { readonly kind: 'invalid'; readonly reason: string }
7
+
8
+ export function resolveIntentTarget(shell: Shell, to: string | undefined): IntentTarget {
9
+ if (to === undefined) {
10
+ return shell.parent !== null
11
+ ? { kind: 'parent' }
12
+ : { kind: 'invalid', reason: 'no target — pass opts.to (a child windowId) from a root shell' }
13
+ }
14
+ if (to === 'parent') {
15
+ return shell.parent !== null
16
+ ? { kind: 'parent' }
17
+ : { kind: 'invalid', reason: "opts.to 'parent' but this shell has no parent channel" }
18
+ }
19
+ return { kind: 'child', windowId: to }
20
+ }
@@ -1,4 +1,4 @@
1
- import type { IntentMessage, IntentRegistry, Shell } from '@astrale-os/shell'
1
+ import type { IntentMessage, IntentRegistry } from '@astrale-os/shell'
2
2
 
3
3
  /**
4
4
  * useSendIntent (API §11) — a stable typed sender. Each call attaches a
@@ -13,6 +13,7 @@ import type { IntentPayload, IntentReply } from './envelope.js'
13
13
 
14
14
  import { useShell } from '../session/shell.hook.js'
15
15
  import { INTENT_REPLY, NOOP, intentMessage } from './envelope.js'
16
+ import { resolveIntentTarget } from './resolve-intent-target.js'
16
17
 
17
18
  /** The typed sender returned by {@link useSendIntent}. */
18
19
  export interface SendIntent {
@@ -24,25 +25,6 @@ export interface SendIntent {
24
25
  ): Promise<IntentReply<K> | void>
25
26
  }
26
27
 
27
- type Target =
28
- | { readonly kind: 'parent' }
29
- | { readonly kind: 'child'; readonly windowId: string }
30
- | { readonly kind: 'invalid'; readonly reason: string }
31
-
32
- function resolveTarget(shell: Shell, to: string | undefined): Target {
33
- if (to === undefined) {
34
- return shell.parent !== null
35
- ? { kind: 'parent' }
36
- : { kind: 'invalid', reason: 'no target — pass opts.to (a child windowId) from a root shell' }
37
- }
38
- if (to === 'parent') {
39
- return shell.parent !== null
40
- ? { kind: 'parent' }
41
- : { kind: 'invalid', reason: "opts.to 'parent' but this shell has no parent channel" }
42
- }
43
- return { kind: 'child', windowId: to }
44
- }
45
-
46
28
  export function useSendIntent(): SendIntent {
47
29
  const shell = useShell()
48
30
  // Unmount settlers for in-flight sends, so a pending reply resolves on teardown.
@@ -61,7 +43,7 @@ export function useSendIntent(): SendIntent {
61
43
  payload: IntentPayload<K>,
62
44
  opts?: { to?: 'parent' | string },
63
45
  ): Promise<IntentReply<K> | void> => {
64
- const target = resolveTarget(shell, opts?.to)
46
+ const target = resolveIntentTarget(shell, opts?.to)
65
47
  if (target.kind === 'invalid') {
66
48
  return Promise.reject(new Error(`useSendIntent: ${target.reason}`))
67
49
  }