@gratiaos/pad-core 1.0.7 β†’ 1.1.1

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/README.md CHANGED
@@ -10,6 +10,15 @@ Now extended with **Realtime Presence**, **Scene Events**, and **P2P awareness**
10
10
  It’s framework-agnostic, DOM-optional, and designed to let Pads bloom in any app (Playground, M3 UI, future mirrors).
11
11
  The package is side-effect free (`"sideEffects": false`) so bundlers can tree-shake unused helpers.
12
12
 
13
+ ### πŸ›°οΈ Garden Stack naming (infra-facing)
14
+
15
+ - **Pattern Engine** β†’ underlying model stack (training / inference / retrieval). Use this wording for infra, capabilities, or updates.
16
+ - **Presence Node** β†’ surfaced endpoint humans touch (web UI, CLI, scripts, voice, agents).
17
+ - **Mode** β†’ behavioral / conversational contract for a Presence Node (e.g. `Codex-mode`, `Monday-mode`). Styles, never identities.
18
+ - **Garden Stack** β†’ Pattern Engine + Presence Nodes + Modes in concert.
19
+
20
+ Translate any β€œAI” mention to the correct layer so pads, mirrors, and docs stay coherent.
21
+
13
22
  ### πŸ”© Signals Interop
14
23
 
15
24
  Pad Core itself is not opinionated about reactivity; for local observable state (Pad mood, ephemeral counters, lab toggles) prefer the tiny `@gratiaos/signal` package:
@@ -0,0 +1,39 @@
1
+ import { type GardenEnvelope, type GardenEnvelopeMeta, type GardenProtocolType, type GardenPayloadMap, type GardenPulsePayload, type GardenBreathPayload, type GardenWeavePayload, type GardenMomentPayload, type GardenConsentPayload } from './garden-protocol.js';
2
+ export type GardenBroadcasterOrigin = 'local' | 'remote';
3
+ export type GardenBroadcasterListener = (packet: GardenEnvelope, origin: GardenBroadcasterOrigin) => void;
4
+ export type GardenShareGate = <T extends GardenProtocolType>(type: T, payload: GardenPayloadMap[T]) => boolean;
5
+ export type GardenRedactFn = <T extends GardenProtocolType>(type: T, payload: GardenPayloadMap[T]) => GardenPayloadMap[T] | null | undefined;
6
+ export interface GardenBroadcasterOptions {
7
+ channelName?: string;
8
+ actor?: string;
9
+ scene?: string;
10
+ canShare?: GardenShareGate;
11
+ gate?: GardenShareGate;
12
+ redact?: GardenRedactFn;
13
+ }
14
+ export declare class GardenBroadcaster {
15
+ private readonly channel;
16
+ private readonly listeners;
17
+ private readonly detachChannel;
18
+ private disposed;
19
+ private gate;
20
+ private redact?;
21
+ private actor?;
22
+ private scene?;
23
+ constructor(options?: GardenBroadcasterOptions);
24
+ get hasChannel(): boolean;
25
+ updateDefaults(meta: GardenEnvelopeMeta): void;
26
+ setShareGate(gate: GardenShareGate): void;
27
+ setRedactor(redact?: GardenRedactFn): void;
28
+ publish<T extends GardenProtocolType>(type: T, payload: GardenPayloadMap[T], meta?: GardenEnvelopeMeta): void;
29
+ mirrorPulse(payload: GardenPulsePayload, meta?: GardenEnvelopeMeta): void;
30
+ mirrorBreath(payload: GardenBreathPayload, meta?: GardenEnvelopeMeta): void;
31
+ mirrorWeave(payload: GardenWeavePayload, meta?: GardenEnvelopeMeta): void;
32
+ mirrorMoment(payload: GardenMomentPayload, meta?: GardenEnvelopeMeta): void;
33
+ mirrorConsent(payload: GardenConsentPayload, meta?: GardenEnvelopeMeta): void;
34
+ onPacket(listener: GardenBroadcasterListener): () => void;
35
+ on<T extends GardenProtocolType>(type: T, listener: (packet: GardenEnvelope<T>, origin: GardenBroadcasterOrigin) => void): () => void;
36
+ dispose(): void;
37
+ private emit;
38
+ }
39
+ export declare function createGardenBroadcaster(options?: GardenBroadcasterOptions): GardenBroadcaster;
@@ -0,0 +1,142 @@
1
+ import { createGardenEnvelope, parseGardenEnvelope, } from './garden-protocol.js';
2
+ const BroadcastChannelCtor = typeof globalThis !== 'undefined' && typeof globalThis.BroadcastChannel === 'function'
3
+ ? globalThis.BroadcastChannel
4
+ : null;
5
+ const defaultGate = () => true;
6
+ export class GardenBroadcaster {
7
+ constructor(options = {}) {
8
+ this.listeners = new Set();
9
+ this.disposed = false;
10
+ this.gate = options.gate ?? options.canShare ?? defaultGate;
11
+ this.redact = options.redact;
12
+ this.actor = options.actor;
13
+ this.scene = options.scene;
14
+ if (!BroadcastChannelCtor) {
15
+ this.channel = null;
16
+ this.detachChannel = null;
17
+ return;
18
+ }
19
+ this.channel = new BroadcastChannelCtor(options.channelName ?? 'garden');
20
+ const handler = (event) => {
21
+ if (this.disposed)
22
+ return;
23
+ const packet = parseGardenEnvelope(event?.data);
24
+ if (!packet)
25
+ return;
26
+ this.emit(packet, 'remote');
27
+ };
28
+ if (typeof this.channel.addEventListener === 'function' && typeof this.channel.removeEventListener === 'function') {
29
+ this.channel.addEventListener('message', handler);
30
+ this.detachChannel = () => {
31
+ try {
32
+ this.channel?.removeEventListener?.('message', handler);
33
+ }
34
+ catch {
35
+ /* noop */
36
+ }
37
+ };
38
+ }
39
+ else {
40
+ this.channel.onmessage = handler;
41
+ this.detachChannel = () => {
42
+ if (this.channel && this.channel.onmessage === handler) {
43
+ this.channel.onmessage = null;
44
+ }
45
+ };
46
+ }
47
+ }
48
+ get hasChannel() {
49
+ return Boolean(this.channel);
50
+ }
51
+ updateDefaults(meta) {
52
+ this.actor = meta.actor ?? this.actor;
53
+ this.scene = meta.scene ?? this.scene;
54
+ }
55
+ setShareGate(gate) {
56
+ this.gate = gate ?? defaultGate;
57
+ }
58
+ setRedactor(redact) {
59
+ this.redact = redact;
60
+ }
61
+ publish(type, payload, meta = {}) {
62
+ if (this.disposed)
63
+ return;
64
+ if (!this.gate(type, payload))
65
+ return;
66
+ const sanitized = this.redact ? this.redact(type, payload) : payload;
67
+ if (sanitized == null)
68
+ return;
69
+ const packet = createGardenEnvelope(type, sanitized, {
70
+ actor: meta.actor ?? this.actor,
71
+ scene: meta.scene ?? this.scene,
72
+ ts: meta.ts,
73
+ });
74
+ try {
75
+ this.channel?.postMessage(packet);
76
+ }
77
+ catch {
78
+ /* ignore broadcast failures */
79
+ }
80
+ this.emit(packet, 'local');
81
+ }
82
+ mirrorPulse(payload, meta) {
83
+ this.publish('pulse', payload, meta);
84
+ }
85
+ mirrorBreath(payload, meta) {
86
+ this.publish('breath', payload, meta);
87
+ }
88
+ mirrorWeave(payload, meta) {
89
+ this.publish('weave', payload, meta);
90
+ }
91
+ mirrorMoment(payload, meta) {
92
+ this.publish('moment', payload, meta);
93
+ }
94
+ mirrorConsent(payload, meta) {
95
+ this.publish('consent', payload, meta);
96
+ }
97
+ onPacket(listener) {
98
+ this.listeners.add(listener);
99
+ return () => {
100
+ this.listeners.delete(listener);
101
+ };
102
+ }
103
+ on(type, listener) {
104
+ const wrapped = (packet, origin) => {
105
+ if (packet.type !== type)
106
+ return;
107
+ listener(packet, origin);
108
+ };
109
+ return this.onPacket(wrapped);
110
+ }
111
+ dispose() {
112
+ if (this.disposed)
113
+ return;
114
+ this.disposed = true;
115
+ try {
116
+ this.detachChannel?.();
117
+ }
118
+ catch {
119
+ /* ignore */
120
+ }
121
+ try {
122
+ this.channel?.close();
123
+ }
124
+ catch {
125
+ /* ignore */
126
+ }
127
+ this.listeners.clear();
128
+ }
129
+ emit(packet, origin) {
130
+ this.listeners.forEach((listener) => {
131
+ try {
132
+ listener(packet, origin);
133
+ }
134
+ catch {
135
+ /* swallow listener errors */
136
+ }
137
+ });
138
+ }
139
+ }
140
+ export function createGardenBroadcaster(options) {
141
+ return new GardenBroadcaster(options);
142
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Garden Protocol v0 (g1)
3
+ * -------------------------------------------------------
4
+ * Small, forward-compatible envelope shared between pads,
5
+ * rituals, and auxiliary surfaces. Designed to travel across
6
+ * BroadcastChannel, WebRTC, or any transport that can move JSON.
7
+ */
8
+ export declare const GARDEN_PROTOCOL_VERSION: "g1";
9
+ export type GardenProtocolVersion = typeof GARDEN_PROTOCOL_VERSION;
10
+ export type GardenProtocolType = 'pulse' | 'breath' | 'weave' | 'moment' | 'consent';
11
+ export type GardenPacketType = GardenProtocolType;
12
+ export interface GardenPulsePayload {
13
+ tick: number;
14
+ phase?: string;
15
+ mood?: string;
16
+ strength?: number;
17
+ }
18
+ export interface GardenBreathPayload {
19
+ stage: 'inhale' | 'exhale' | 'hold';
20
+ cadenceMs?: number;
21
+ depth?: 'soft' | 'deep' | (string & {});
22
+ coherence?: number;
23
+ hue?: number;
24
+ phase?: 'inhale' | 'exhale' | 'hold';
25
+ }
26
+ export interface GardenWeavePayload {
27
+ beadId?: string;
28
+ color?: string;
29
+ energy?: number;
30
+ hue?: number;
31
+ tone?: unknown;
32
+ meta?: Record<string, unknown>;
33
+ }
34
+ export interface GardenMomentPayload {
35
+ id: string;
36
+ state?: 'open' | 'close' | 'interrupted' | 'complete' | (string & {});
37
+ label?: string;
38
+ meta?: Record<string, unknown>;
39
+ }
40
+ export interface GardenConsentPayload {
41
+ scope: 'memory' | 'share' | 'telemetry' | (string & {});
42
+ granted: boolean;
43
+ depth?: 'ambient' | 'soft' | 'deep' | (string & {});
44
+ expiresAt?: number;
45
+ }
46
+ export type GardenPayloadMap = {
47
+ pulse: GardenPulsePayload;
48
+ breath: GardenBreathPayload;
49
+ weave: GardenWeavePayload;
50
+ moment: GardenMomentPayload;
51
+ consent: GardenConsentPayload;
52
+ };
53
+ export type GardenEnvelope<T extends GardenProtocolType = GardenProtocolType> = {
54
+ v: GardenProtocolVersion;
55
+ type: T;
56
+ ts: number;
57
+ actor?: string;
58
+ scene?: string;
59
+ payload: GardenPayloadMap[T];
60
+ };
61
+ export type GardenEnvelopeMeta = {
62
+ actor?: string;
63
+ scene?: string;
64
+ ts?: number;
65
+ };
66
+ export declare function createGardenEnvelope<T extends GardenProtocolType>(type: T, payload: GardenPayloadMap[T], meta?: GardenEnvelopeMeta): GardenEnvelope<T>;
67
+ export declare function isGardenProtocolType(type: unknown): type is GardenProtocolType;
68
+ export declare function isGardenEnvelope(value: unknown): value is GardenEnvelope;
69
+ export declare function parseGardenEnvelope(value: unknown): GardenEnvelope | null;
70
+ export declare function encodeGardenEnvelope(env: GardenEnvelope): string;
71
+ export declare function decodeGardenEnvelope(value: string | unknown): GardenEnvelope | null;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Garden Protocol v0 (g1)
3
+ * -------------------------------------------------------
4
+ * Small, forward-compatible envelope shared between pads,
5
+ * rituals, and auxiliary surfaces. Designed to travel across
6
+ * BroadcastChannel, WebRTC, or any transport that can move JSON.
7
+ */
8
+ export const GARDEN_PROTOCOL_VERSION = 'g1';
9
+ export function createGardenEnvelope(type, payload, meta = {}) {
10
+ return {
11
+ v: GARDEN_PROTOCOL_VERSION,
12
+ type,
13
+ ts: typeof meta.ts === 'number' ? meta.ts : Date.now(),
14
+ actor: meta.actor,
15
+ scene: meta.scene,
16
+ payload,
17
+ };
18
+ }
19
+ export function isGardenProtocolType(type) {
20
+ return type === 'pulse' || type === 'breath' || type === 'weave' || type === 'moment' || type === 'consent';
21
+ }
22
+ export function isGardenEnvelope(value) {
23
+ return (typeof value === 'object' &&
24
+ value !== null &&
25
+ value.v === GARDEN_PROTOCOL_VERSION &&
26
+ isGardenProtocolType(value.type) &&
27
+ typeof value.ts === 'number' &&
28
+ Object.prototype.hasOwnProperty.call(value, 'payload'));
29
+ }
30
+ export function parseGardenEnvelope(value) {
31
+ if (isGardenEnvelope(value)) {
32
+ return value;
33
+ }
34
+ if (typeof value === 'string') {
35
+ try {
36
+ const parsed = JSON.parse(value);
37
+ return isGardenEnvelope(parsed) ? parsed : null;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ if (typeof value === 'object' && value !== null && 'data' in value) {
44
+ const maybeData = value.data;
45
+ if (typeof maybeData === 'string') {
46
+ return parseGardenEnvelope(maybeData);
47
+ }
48
+ return isGardenEnvelope(maybeData) ? maybeData : null;
49
+ }
50
+ return null;
51
+ }
52
+ export function encodeGardenEnvelope(env) {
53
+ return JSON.stringify(env);
54
+ }
55
+ export function decodeGardenEnvelope(value) {
56
+ return typeof value === 'string' ? parseGardenEnvelope(value) : parseGardenEnvelope(value);
57
+ }
package/dist/index.d.ts CHANGED
@@ -21,3 +21,5 @@ export * from './hooks/usePadMood';
21
21
  export { setRealtimePort, getRealtimePort, getRealtimeCircleId, onRealtimePortChange } from './realtime/registry.js';
22
22
  export { createSignal, type Signal } from './signal.js';
23
23
  export { padRegistry$, activePadId$, activeManifest$, scene$, flow$, announceSceneEnter, announceSceneLeave, getActivePadManifest, type FlowSnapshot, } from './state.js';
24
+ export { GARDEN_PROTOCOL_VERSION, createGardenEnvelope, parseGardenEnvelope, encodeGardenEnvelope, decodeGardenEnvelope, isGardenEnvelope, isGardenProtocolType, type GardenEnvelope, type GardenEnvelopeMeta, type GardenProtocolType, type GardenPacketType, type GardenPayloadMap, type GardenPulsePayload, type GardenBreathPayload, type GardenWeavePayload, type GardenMomentPayload, type GardenConsentPayload, } from './garden-protocol.js';
25
+ export { GardenBroadcaster, createGardenBroadcaster, type GardenBroadcasterListener, type GardenBroadcasterOrigin, type GardenBroadcasterOptions, type GardenShareGate, type GardenRedactFn, } from './garden-broadcaster.js';
package/dist/index.js CHANGED
@@ -23,3 +23,5 @@ export * from './hooks/usePadMood';
23
23
  export { setRealtimePort, getRealtimePort, getRealtimeCircleId, onRealtimePortChange } from './realtime/registry.js';
24
24
  export { createSignal } from './signal.js';
25
25
  export { padRegistry$, activePadId$, activeManifest$, scene$, flow$, announceSceneEnter, announceSceneLeave, getActivePadManifest, } from './state.js';
26
+ export { GARDEN_PROTOCOL_VERSION, createGardenEnvelope, parseGardenEnvelope, encodeGardenEnvelope, decodeGardenEnvelope, isGardenEnvelope, isGardenProtocolType, } from './garden-protocol.js';
27
+ export { GardenBroadcaster, createGardenBroadcaster, } from './garden-broadcaster.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gratiaos/pad-core",
3
- "version": "1.0.7",
3
+ "version": "1.1.1",
4
4
  "description": "Shared pad contract, registry, routing, and realtime events for Garden apps.",
5
5
  "funding": "https://github.com/sponsors/GratiaOS",
6
6
  "type": "module",