@xenosystem/blocks 0.1.0
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/LICENSE +10 -0
- package/dist/auth/index.d.ts +121 -0
- package/dist/auth/index.js +274 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +5 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Copyright (c) XENO Corporation. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software is proprietary and confidential. It is UNLICENSED: no licence,
|
|
4
|
+
express or implied, is granted to any person to use, copy, modify, merge,
|
|
5
|
+
publish, distribute, sublicense, or sell copies of this software, except under a
|
|
6
|
+
separate written agreement with XENO Corporation.
|
|
7
|
+
|
|
8
|
+
This file restates the `"license": "UNLICENSED"` declaration already present in
|
|
9
|
+
every package manifest. It exists so that the declaration travels inside the
|
|
10
|
+
published tarball, where package.json alone is easy to miss.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { PanelModule, PanelManifest } from '@xenosystem/panel-sdk';
|
|
4
|
+
import { XenoAccountStatus, XenoAccountIdentity, XenoAccountActionKind } from '@xenosystem/panel-account';
|
|
5
|
+
export * from '@xenosystem/panel-account';
|
|
6
|
+
|
|
7
|
+
interface CreateAuthGatePanelOptions {
|
|
8
|
+
/** What renders behind the gate once it is `open`. A product passes its app; the harness a fixture. */
|
|
9
|
+
children?: () => ReactNode;
|
|
10
|
+
heroSrc?: string;
|
|
11
|
+
now?: () => number;
|
|
12
|
+
}
|
|
13
|
+
declare function createAuthGatePanel(options?: CreateAuthGatePanelOptions): PanelModule;
|
|
14
|
+
declare const authGatePanel: PanelModule;
|
|
15
|
+
|
|
16
|
+
declare const AUTH_GATE_PANEL_ID = "xeno.core.auth-gate";
|
|
17
|
+
/**
|
|
18
|
+
* The gate's manifest. It declares ONE input (the two axes) and ONE output (an intent), no
|
|
19
|
+
* commands: an agent-invocable "sign in" is by definition not interactive (AUTH L8), and a gate
|
|
20
|
+
* an agent can open is not a gate.
|
|
21
|
+
*/
|
|
22
|
+
declare const authGateManifest: PanelManifest;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `xeno.core.auth-gate` — the door in front of a XENO product.
|
|
26
|
+
*
|
|
27
|
+
* Contract: `XENO AUTH - AUTH GATE DELTA.md` §2–§3. Two host-pushed AXES, one derived PHASE.
|
|
28
|
+
*
|
|
29
|
+
* 🔴 The gate never derives a FACT. Whether the person is signed in and whether the build is
|
|
30
|
+
* licensed are decided in the product's main process (AUTH L9, §12.3; LICENCE-ENFORCEMENT §1
|
|
31
|
+
* "main process, never the renderer"). What is derived here is only which plate to show for the
|
|
32
|
+
* facts the host reported.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** LICENCE-ENFORCEMENT §3 — the four states every product must handle honestly. */
|
|
36
|
+
type XenoLicenceState = 'licensed' | 'unlicensed' | 'expired-offline' | 'update-required';
|
|
37
|
+
/** What the host pushes on the `auth` input. Contains NO token, by construction (AUTH L9). */
|
|
38
|
+
interface XenoAuthGateState {
|
|
39
|
+
/** The account axis — `panel-account`'s vocabulary, not a second one. */
|
|
40
|
+
account: XenoAccountStatus;
|
|
41
|
+
/** The licence axis; `checking` while the main-process check has not answered yet. */
|
|
42
|
+
licence: XenoLicenceState | 'checking';
|
|
43
|
+
/**
|
|
44
|
+
* Whether the host CAN sign someone in at all: `unavailable` when the OS keystore is unusable
|
|
45
|
+
* (AUTH L9 hard-fail) or no account authority is composed. A sign-in button that cannot work
|
|
46
|
+
* is worse than none — the gate says why instead.
|
|
47
|
+
*/
|
|
48
|
+
sdk: 'ready' | 'unavailable';
|
|
49
|
+
/** An interactive sign-in is in flight (the browser is open). Keeps the `sign-in` plate, disables its button. */
|
|
50
|
+
pending?: boolean;
|
|
51
|
+
/** Who is signed in, when known. Display only. */
|
|
52
|
+
identity?: XenoAccountIdentity;
|
|
53
|
+
/** The host's own sentence for the current state — the reason a keystore is unusable, the plan that is missing, the floor a build is below. */
|
|
54
|
+
message?: string;
|
|
55
|
+
/** For `expired-offline`: when the licence was last confirmed, so the plate can say how long ago. */
|
|
56
|
+
lastVerifiedAt?: number;
|
|
57
|
+
/** Which intents the host implements. A missing one hides its affordance (COMPONENTS §1.7). */
|
|
58
|
+
capabilities?: Partial<Record<XenoAuthGateIntentKind, boolean>>;
|
|
59
|
+
}
|
|
60
|
+
/** What the gate shows. Exactly one at a time; `open` renders nothing of the gate at all. */
|
|
61
|
+
type XenoAuthGatePhase = 'unavailable' | 'checking' | 'sign-in' | 'update-required' | 'expired-offline' | 'unlicensed' | 'open';
|
|
62
|
+
/**
|
|
63
|
+
* DELTA §2, in order — first match wins. Pure, so a host can be tested against it without a DOM.
|
|
64
|
+
*/
|
|
65
|
+
declare function deriveAuthGatePhase(state: XenoAuthGateState): XenoAuthGatePhase;
|
|
66
|
+
/**
|
|
67
|
+
* DELTA §2, last paragraph: "fail OPEN on a network error, CLOSED on an explicit refusal" is the
|
|
68
|
+
* HOST's rule, but the gate can see one combination the rule forbids — an account the host could
|
|
69
|
+
* not reach (`offline`) reported alongside an explicit `unlicensed`. Nobody refused anyone; the
|
|
70
|
+
* network did. The gate shows the honest plate and names the contradiction.
|
|
71
|
+
*/
|
|
72
|
+
declare function hostContradiction(state: XenoAuthGateState): string | null;
|
|
73
|
+
/** The only way out of the gate. `panel-account`'s intents plus the two a door needs (DELTA §3). */
|
|
74
|
+
type XenoAuthGateIntentKind = Extract<XenoAccountActionKind, 'signIn' | 'signOut' | 'refresh' | 'manageBilling'> | 'cancelSignIn' | 'openDownload';
|
|
75
|
+
interface XenoAuthGateIntent {
|
|
76
|
+
kind: XenoAuthGateIntentKind;
|
|
77
|
+
}
|
|
78
|
+
/** Which intents each phase may offer. The view never offers one outside this table. */
|
|
79
|
+
declare const PHASE_INTENTS: Readonly<Record<XenoAuthGatePhase, readonly XenoAuthGateIntentKind[]>>;
|
|
80
|
+
declare function intentOffered(state: XenoAuthGateState, kind: XenoAuthGateIntentKind): boolean;
|
|
81
|
+
/** The initial state before the host has said anything. */
|
|
82
|
+
declare const AUTH_GATE_INITIAL: XenoAuthGateState;
|
|
83
|
+
declare function formatSince(lastVerifiedAt: number | undefined, now: number): string | null;
|
|
84
|
+
|
|
85
|
+
interface AuthGateHostBridge {
|
|
86
|
+
emit: (portId: 'intent', value: XenoAuthGateIntent) => void;
|
|
87
|
+
/** Where a host contradiction is reported. Default: console.warn. */
|
|
88
|
+
warn?: (message: string) => void;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Holds the last pushed state and derives the phase. Deliberately tiny: a controller that
|
|
92
|
+
* remembered more than the host said would be a place for a fact to be invented.
|
|
93
|
+
*/
|
|
94
|
+
declare class AuthGateController {
|
|
95
|
+
private readonly host;
|
|
96
|
+
private state;
|
|
97
|
+
private readonly listeners;
|
|
98
|
+
private lastWarned;
|
|
99
|
+
constructor(host: AuthGateHostBridge);
|
|
100
|
+
setState(next: XenoAuthGateState): void;
|
|
101
|
+
getState(): XenoAuthGateState;
|
|
102
|
+
getPhase(): XenoAuthGatePhase;
|
|
103
|
+
offers(kind: XenoAuthGateIntentKind): boolean;
|
|
104
|
+
/** Emit an intent — only if this phase offers it. A hidden button cannot be pressed by code either. */
|
|
105
|
+
intend(kind: XenoAuthGateIntentKind): boolean;
|
|
106
|
+
subscribe(listener: () => void): () => void;
|
|
107
|
+
dispose(): void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface AuthGateViewProps {
|
|
111
|
+
controller: AuthGateController;
|
|
112
|
+
productName: string;
|
|
113
|
+
/** Rendered ONLY when the phase is `open`. */
|
|
114
|
+
children?: ReactNode;
|
|
115
|
+
/** Optional hero image (Hub's login art). */
|
|
116
|
+
heroSrc?: string;
|
|
117
|
+
now?: () => number;
|
|
118
|
+
}
|
|
119
|
+
declare function AuthGateView({ controller, productName, children, heroSrc, now }: AuthGateViewProps): react.JSX.Element;
|
|
120
|
+
|
|
121
|
+
export { AUTH_GATE_INITIAL, AUTH_GATE_PANEL_ID, AuthGateController, type AuthGateHostBridge, AuthGateView, type AuthGateViewProps, type CreateAuthGatePanelOptions, PHASE_INTENTS, type XenoAuthGateIntent, type XenoAuthGateIntentKind, type XenoAuthGatePhase, type XenoAuthGateState, type XenoLicenceState, authGateManifest, authGatePanel, createAuthGatePanel, deriveAuthGatePhase, formatSince, hostContradiction, intentOffered };
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
// src/auth/gate/panel.ts
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { createRoot } from "react-dom/client";
|
|
4
|
+
import { bindConfig } from "@xenosystem/panel-sdk";
|
|
5
|
+
|
|
6
|
+
// src/auth/gate/types.ts
|
|
7
|
+
function deriveAuthGatePhase(state) {
|
|
8
|
+
if (state.sdk === "unavailable") return "unavailable";
|
|
9
|
+
if (state.account === "unknown") return "checking";
|
|
10
|
+
if (state.account === "signedOut" || state.account === "expired") return "sign-in";
|
|
11
|
+
if (state.licence === "checking") return "checking";
|
|
12
|
+
if (state.licence === "update-required") return "update-required";
|
|
13
|
+
if (state.licence === "expired-offline") return "expired-offline";
|
|
14
|
+
if (state.licence === "unlicensed") return "unlicensed";
|
|
15
|
+
return "open";
|
|
16
|
+
}
|
|
17
|
+
function hostContradiction(state) {
|
|
18
|
+
if (state.account === "offline" && state.licence === "unlicensed") {
|
|
19
|
+
return "host reported unlicensed while offline \u2014 a network error is not a refusal (LICENCE-ENFORCEMENT \xA74)";
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
var PHASE_INTENTS = {
|
|
24
|
+
unavailable: ["refresh"],
|
|
25
|
+
checking: [],
|
|
26
|
+
"sign-in": ["signIn", "cancelSignIn"],
|
|
27
|
+
"update-required": ["openDownload", "signOut"],
|
|
28
|
+
"expired-offline": ["refresh", "signOut"],
|
|
29
|
+
unlicensed: ["manageBilling", "refresh", "signOut"],
|
|
30
|
+
open: []
|
|
31
|
+
};
|
|
32
|
+
function intentOffered(state, kind) {
|
|
33
|
+
const phase = deriveAuthGatePhase(state);
|
|
34
|
+
if (!PHASE_INTENTS[phase].includes(kind)) return false;
|
|
35
|
+
if (kind === "cancelSignIn") return state.pending === true;
|
|
36
|
+
if (kind === "signIn") return state.pending !== true;
|
|
37
|
+
if (state.capabilities && state.capabilities[kind] === false) return false;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
var AUTH_GATE_INITIAL = { account: "unknown", licence: "checking", sdk: "ready" };
|
|
41
|
+
function formatSince(lastVerifiedAt, now) {
|
|
42
|
+
if (!lastVerifiedAt) return null;
|
|
43
|
+
const days = Math.floor(Math.max(0, now - lastVerifiedAt) / 864e5);
|
|
44
|
+
if (days <= 0) return "today";
|
|
45
|
+
if (days === 1) return "yesterday";
|
|
46
|
+
return `${days} days ago`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/auth/gate/controller.ts
|
|
50
|
+
var AuthGateController = class {
|
|
51
|
+
constructor(host) {
|
|
52
|
+
this.host = host;
|
|
53
|
+
}
|
|
54
|
+
host;
|
|
55
|
+
state = AUTH_GATE_INITIAL;
|
|
56
|
+
listeners = /* @__PURE__ */ new Set();
|
|
57
|
+
lastWarned = null;
|
|
58
|
+
setState(next) {
|
|
59
|
+
this.state = next;
|
|
60
|
+
const contradiction = hostContradiction(next);
|
|
61
|
+
if (contradiction && contradiction !== this.lastWarned) {
|
|
62
|
+
;
|
|
63
|
+
(this.host.warn ?? ((m) => console.warn(`[xeno.core.auth-gate] ${m}`)))(contradiction);
|
|
64
|
+
this.lastWarned = contradiction;
|
|
65
|
+
}
|
|
66
|
+
for (const l of this.listeners) l();
|
|
67
|
+
}
|
|
68
|
+
getState() {
|
|
69
|
+
return this.state;
|
|
70
|
+
}
|
|
71
|
+
getPhase() {
|
|
72
|
+
return deriveAuthGatePhase(this.state);
|
|
73
|
+
}
|
|
74
|
+
offers(kind) {
|
|
75
|
+
return intentOffered(this.state, kind);
|
|
76
|
+
}
|
|
77
|
+
/** Emit an intent — only if this phase offers it. A hidden button cannot be pressed by code either. */
|
|
78
|
+
intend(kind) {
|
|
79
|
+
if (!this.offers(kind)) return false;
|
|
80
|
+
this.host.emit("intent", { kind });
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
subscribe(listener) {
|
|
84
|
+
this.listeners.add(listener);
|
|
85
|
+
return () => this.listeners.delete(listener);
|
|
86
|
+
}
|
|
87
|
+
dispose() {
|
|
88
|
+
this.listeners.clear();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/auth/gate/manifest.ts
|
|
93
|
+
var AUTH_GATE_PANEL_ID = "xeno.core.auth-gate";
|
|
94
|
+
var authGateManifest = {
|
|
95
|
+
id: AUTH_GATE_PANEL_ID,
|
|
96
|
+
version: "0.1.0",
|
|
97
|
+
title: "Auth Gate",
|
|
98
|
+
icon: "lock",
|
|
99
|
+
description: "The door in front of a XENO product. Shows sign-in (system browser only) and the four licence states from host-pushed facts; renders the product only when signed in AND licensed. Holds no token, calls no SDK.",
|
|
100
|
+
defaultSlot: "center",
|
|
101
|
+
inputs: [
|
|
102
|
+
{
|
|
103
|
+
id: "auth",
|
|
104
|
+
name: "Auth",
|
|
105
|
+
type: "object",
|
|
106
|
+
description: "{account, licence, sdk, pending?, identity?, message?, lastVerifiedAt?, capabilities?}. Two facts the host decided in its main process. Contains NO token \u2014 AUTH L9.",
|
|
107
|
+
multiple: false
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
outputs: [
|
|
111
|
+
{
|
|
112
|
+
id: "intent",
|
|
113
|
+
name: "Intent",
|
|
114
|
+
type: "object",
|
|
115
|
+
description: "{kind}: signIn | cancelSignIn | signOut | refresh | manageBilling | openDownload. An INTENT the host performs; the gate changes nothing itself."
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
commands: [],
|
|
119
|
+
config: [
|
|
120
|
+
{ key: "productName", label: "Product name", type: "text", defaultValue: "XENO", description: 'Named in the copy: "Sign in to use XENO Canvas."' },
|
|
121
|
+
{ key: "productSlug", label: "Product slug", type: "text", defaultValue: "", description: "The platform slug; reported back on intents so the host can open the right download / plan page." }
|
|
122
|
+
],
|
|
123
|
+
capabilities: [],
|
|
124
|
+
sdk: "^1.1.0"
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/auth/gate/react/AuthGateView.tsx
|
|
128
|
+
import { useEffect, useState } from "react";
|
|
129
|
+
import { AuthDoor, SignInForm } from "@xenosystem/components/auth";
|
|
130
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
131
|
+
function AuthGateView({ controller, productName, children, heroSrc, now = () => Date.now() }) {
|
|
132
|
+
const [, force] = useState(0);
|
|
133
|
+
useEffect(() => controller.subscribe(() => force((n) => n + 1)), [controller]);
|
|
134
|
+
const phase = controller.getPhase();
|
|
135
|
+
if (phase === "open") return /* @__PURE__ */ jsx(Fragment, { children });
|
|
136
|
+
const state = controller.getState();
|
|
137
|
+
const copy = plateCopy(phase, productName, state.message, formatSince(state.lastVerifiedAt, now()));
|
|
138
|
+
const action = (id, label, variant = "primary") => controller.offers(id) ? [{ id, label, variant, onClick: () => controller.intend(id) }] : [];
|
|
139
|
+
const actions = [
|
|
140
|
+
...phase === "sign-in" && state.pending ? [{ id: "pending", label: "Finish in your browser\u2026", variant: "primary", disabled: true }] : [],
|
|
141
|
+
...action("signIn", "Sign in to XENO"),
|
|
142
|
+
...action("cancelSignIn", "Cancel", "quiet"),
|
|
143
|
+
...action("openDownload", `Download the latest ${productName}`),
|
|
144
|
+
...action("manageBilling", "Choose a plan"),
|
|
145
|
+
...action("refresh", phase === "unlicensed" || phase === "expired-offline" ? "Check again" : "Try again", phase === "unlicensed" ? "quiet" : "primary"),
|
|
146
|
+
...action("signOut", "Sign out", "quiet")
|
|
147
|
+
];
|
|
148
|
+
const identity = state.identity && phase !== "sign-in" ? state.identity.email ?? state.identity.name ?? state.identity.sub : void 0;
|
|
149
|
+
return /* @__PURE__ */ jsx(
|
|
150
|
+
AuthDoor,
|
|
151
|
+
{
|
|
152
|
+
label: `${productName} sign-in`,
|
|
153
|
+
rootAttributes: { "data-xeno-auth-gate": phase },
|
|
154
|
+
hero: {
|
|
155
|
+
imageSrc: heroSrc,
|
|
156
|
+
headline: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
157
|
+
"One account.",
|
|
158
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
159
|
+
"Every XENO product."
|
|
160
|
+
] }),
|
|
161
|
+
lead: `Sign in once and ${productName} \u2014 and every other XENO app \u2014 runs under your plan, your credits and your files.`,
|
|
162
|
+
stats: [
|
|
163
|
+
{ value: "1", label: "Account" },
|
|
164
|
+
{ value: "Yours", label: "Files stay put" },
|
|
165
|
+
{ value: "Browser", label: "Sign-in, never in-app" }
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
children: /* @__PURE__ */ jsx(
|
|
169
|
+
SignInForm,
|
|
170
|
+
{
|
|
171
|
+
phase,
|
|
172
|
+
tag: copy.tag,
|
|
173
|
+
title: copy.title,
|
|
174
|
+
body: copy.body,
|
|
175
|
+
actions,
|
|
176
|
+
note: phase === "sign-in" && !state.pending ? `Your browser opens at xenostudio.ai, where you can continue with Google, GitHub or email. ${productName} never sees your password.` : void 0,
|
|
177
|
+
warning: copy.note,
|
|
178
|
+
identity
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
function plateCopy(phase, product, message, since) {
|
|
185
|
+
switch (phase) {
|
|
186
|
+
case "checking":
|
|
187
|
+
return { title: "One moment", body: `Checking your XENO account\u2026` };
|
|
188
|
+
case "sign-in":
|
|
189
|
+
return { title: "Welcome back", body: message ?? `Sign in to your XENO account to use ${product}.` };
|
|
190
|
+
case "unavailable":
|
|
191
|
+
return { tag: "Sign-in unavailable", title: "Can\u2019t reach your account", body: message ?? `${product} cannot store a sign-in on this machine right now.` };
|
|
192
|
+
case "update-required":
|
|
193
|
+
return { tag: "Update required", title: `Update ${product} to continue`, body: message ?? `This version of ${product} is older than the oldest one still supported. The latest version is a short download away.` };
|
|
194
|
+
case "expired-offline":
|
|
195
|
+
return { tag: "Offline too long", title: "Your plan couldn\u2019t be confirmed", body: `${product} hasn\u2019t been able to reach XENO for 14 days${since ? ` \u2014 last confirmed ${since}` : ""}. Your plan may be fine; connect once and it will pick up where it left off.`, note: message };
|
|
196
|
+
case "unlicensed":
|
|
197
|
+
return { tag: "No active plan", title: `${product} needs a plan`, body: message ?? `Your XENO account doesn\u2019t include ${product} yet. Choose a plan to use it \u2014 nothing on this machine changes until you do.` };
|
|
198
|
+
default:
|
|
199
|
+
return { title: "", body: "" };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/auth/gate/panel.ts
|
|
204
|
+
function createAuthGatePanel(options = {}) {
|
|
205
|
+
return {
|
|
206
|
+
manifest: authGateManifest,
|
|
207
|
+
activate(host) {
|
|
208
|
+
const controller = new AuthGateController({ emit: (port, value) => host.emit(port, value) });
|
|
209
|
+
const resolve = (config) => ({
|
|
210
|
+
productName: typeof config.productName === "string" && config.productName ? config.productName : "XENO"
|
|
211
|
+
});
|
|
212
|
+
let renderConfig = resolve(host.config ?? {});
|
|
213
|
+
let root = null;
|
|
214
|
+
let el = null;
|
|
215
|
+
const draw = () => {
|
|
216
|
+
if (!el) return;
|
|
217
|
+
el.style.position = el.style.position || "relative";
|
|
218
|
+
root ??= createRoot(el);
|
|
219
|
+
root.render(
|
|
220
|
+
createElement(AuthGateView, {
|
|
221
|
+
controller,
|
|
222
|
+
productName: renderConfig.productName,
|
|
223
|
+
heroSrc: options.heroSrc,
|
|
224
|
+
now: options.now,
|
|
225
|
+
children: options.children?.()
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
const unbindConfig = bindConfig(host, (config) => {
|
|
230
|
+
renderConfig = resolve(config);
|
|
231
|
+
draw();
|
|
232
|
+
});
|
|
233
|
+
return {
|
|
234
|
+
render(target) {
|
|
235
|
+
el = target;
|
|
236
|
+
draw();
|
|
237
|
+
},
|
|
238
|
+
onInput(portId, value) {
|
|
239
|
+
if (portId === "auth" && value && typeof value === "object" && "account" in value && "licence" in value && "sdk" in value) {
|
|
240
|
+
controller.setState(value);
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
async onCommand() {
|
|
244
|
+
return;
|
|
245
|
+
},
|
|
246
|
+
dispose() {
|
|
247
|
+
unbindConfig();
|
|
248
|
+
root?.unmount();
|
|
249
|
+
root = null;
|
|
250
|
+
el = null;
|
|
251
|
+
controller.dispose();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
var authGatePanel = createAuthGatePanel();
|
|
258
|
+
|
|
259
|
+
// src/auth/index.ts
|
|
260
|
+
export * from "@xenosystem/panel-account";
|
|
261
|
+
export {
|
|
262
|
+
AUTH_GATE_INITIAL,
|
|
263
|
+
AUTH_GATE_PANEL_ID,
|
|
264
|
+
AuthGateController,
|
|
265
|
+
AuthGateView,
|
|
266
|
+
PHASE_INTENTS,
|
|
267
|
+
authGateManifest,
|
|
268
|
+
authGatePanel,
|
|
269
|
+
createAuthGatePanel,
|
|
270
|
+
deriveAuthGatePhase,
|
|
271
|
+
formatSince,
|
|
272
|
+
hostContradiction,
|
|
273
|
+
intentOffered
|
|
274
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@xenosystem/blocks` — rung 3 of the FRONT ladder — BLOCKS (`XENO FRONT-END HIERARCHY.md`).
|
|
3
|
+
* Families are subpaths: `@xenosystem/blocks/auth`, `/edit`, `/data`, `/time`, `/ops`, `/trust`,
|
|
4
|
+
* `/agent`. This root re-exports nothing on purpose: import the family you mount, so a product
|
|
5
|
+
* carries only it. Naming rule: `XENO PACKAGE NAMING - STANDARD.md`.
|
|
6
|
+
*/
|
|
7
|
+
declare const BLOCKS_VERSION = "0.1.0";
|
|
8
|
+
|
|
9
|
+
export { BLOCKS_VERSION };
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xenosystem/blocks",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./auth": {
|
|
14
|
+
"types": "./dist/auth/index.d.ts",
|
|
15
|
+
"import": "./dist/auth/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@xenosystem/components": "^0.1.0",
|
|
30
|
+
"@xenosystem/elements-react": ">=0.0.1",
|
|
31
|
+
"@xenosystem/panel-account": "^0.1.0",
|
|
32
|
+
"@xenosystem/panel-sdk": "^1.1.0",
|
|
33
|
+
"react": ">=18.0.0",
|
|
34
|
+
"react-dom": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"@types/react": "^19.0.0",
|
|
39
|
+
"@types/react-dom": "^19.0.0",
|
|
40
|
+
"@xenosystem/components": "^0.1.0",
|
|
41
|
+
"@xenosystem/elements-react": "0.0.1",
|
|
42
|
+
"@xenosystem/panel-account": "^0.1.0",
|
|
43
|
+
"@xenosystem/panel-sdk": "^1.1.0",
|
|
44
|
+
"react": "^19.0.0",
|
|
45
|
+
"react-dom": "^19.0.0",
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5.4.0",
|
|
48
|
+
"vitest": "^4.1.0"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
}
|
|
53
|
+
}
|