Export template source from c5854ac7629ac10f984b745270bdd022e2eed236:quixos-instance/packages/web-studio-canvas-runtime
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
src/gen/
|
||||||
|
.quixos/
|
||||||
|
result
|
||||||
|
.yarn/cache/
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.yarn/unplugged/
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"monorepoCommit": "c5854ac7629ac10f984b745270bdd022e2eed236",
|
||||||
|
"sourcePath": "quixos-instance/packages/web-studio-canvas-runtime"
|
||||||
|
}
|
||||||
Vendored
+1
File diff suppressed because one or more lines are too long
+24
@@ -0,0 +1,24 @@
|
|||||||
|
enableScripts: true
|
||||||
|
|
||||||
|
generateDefaultNix: false
|
||||||
|
|
||||||
|
individualNixPackaging: true
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
supportedArchitectures:
|
||||||
|
os:
|
||||||
|
- current
|
||||||
|
- linux
|
||||||
|
cpu:
|
||||||
|
- current
|
||||||
|
- x64
|
||||||
|
- arm64
|
||||||
|
libc:
|
||||||
|
- current
|
||||||
|
- glibc
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- checksum: 271de9a785321a37c564b8e2a6b5cd689850b20572d5fee8ec0a6b8e7a5d4cfb59e533524af2b4a537e00da12828abd062eaec6978556e3dd9149a020db2591b
|
||||||
|
path: .yarn/plugins/yarn-plugin-nixify.cjs
|
||||||
|
spec: "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/yarn-plugin-nixify-patched/raw/commit/4528fdd20b30d869262443b3f044549810e75fb8/dist/yarn-plugin-nixify.js"
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Studio graph capabilities
|
||||||
|
|
||||||
|
This system package implements ordinary Canvas/Placement/Placeable interfaces.
|
||||||
|
It owns no database, web server, Worker, page session, or special presentation
|
||||||
|
object per rendered subject. The workspace binds storage and relationship edges.
|
||||||
|
The checked component is an independent consumer of the same public contracts.
|
||||||
|
|
||||||
|
- `Canvas.create` creates an initialized canvas. The server entry factory uses the
|
||||||
|
workspace host's idempotent root protocol, without a second package-local cache.
|
||||||
|
- `Canvas.place` validates the requested renderer through the subject's portable
|
||||||
|
`Placeable.canPresent` contract and creates one placement with both relationships.
|
||||||
|
- `Canvas.createAndPlace` is an example compound factory: child canvas creation,
|
||||||
|
renderer validation and placement creation share one transaction. An invalid
|
||||||
|
renderer rolls back the child, too. Other domains can compose their own creation
|
||||||
|
ports in exactly this way; there is no frontend business reducer.
|
||||||
|
- `position` and `size` are separate whole-record registers. Concurrent move and
|
||||||
|
resize survive independently; concurrent moves resolve in server acceptance
|
||||||
|
order without mixing one move's x coordinate with another move's y coordinate.
|
||||||
|
- `remove` is explicitly server-only. Deletion needs the full incoming-reference
|
||||||
|
graph; a partial replica cannot safely predict all deletion restrictions and
|
||||||
|
cascades. Removing a placement preserves its subject. The interface does not
|
||||||
|
advertise a portable delete or keep a hidden archive in the canvas query.
|
||||||
|
|
||||||
|
The generic `canPresent<atom Subject>` implementation reads the explicitly granted
|
||||||
|
`reflection catalog [presentations]` port. This exposes only immutable checked
|
||||||
|
presentation IDs, subject contracts and their conforming atoms. It does not expose
|
||||||
|
live object inventory or private state. The dispatcher verifies the concrete
|
||||||
|
receiver; reference expectations supplied by a caller are not conformance proof.
|
||||||
|
A changed presentation catalog participates in the consuming execution group's
|
||||||
|
reuse digest. Unrelated modules do not acquire that dependency.
|
||||||
|
|
||||||
|
Queries have explicit prototype bounds: 100 canvases in navigation and 200
|
||||||
|
placements per open canvas. Title-only cards use their own small input projection.
|
||||||
|
A selected/new placement can retain `PlacementInputs` even if a list excludes it.
|
||||||
|
A larger Studio should add explicit windows or pagination rather than silently
|
||||||
|
pretend these bounded queries cover an arbitrarily large workspace.
|
||||||
|
|
||||||
|
`tools/local-first/studio.nix` builds the source snapshot through the checked
|
||||||
|
artifact builder and tests the generic workspace host. Run
|
||||||
|
`nix build .#checks.x86_64-linux.camino-studio-capabilities` at the monorepo root.
|
||||||
|
These are unpublished fixture resource pins; normal independently retained source
|
||||||
|
assembly and scaffolding are qualified in WI-12. The old checkedServer/Yarn and
|
||||||
|
migration recipes were removed, rather than presenting them as a compatible path.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"component:studio:canvas-card" = {
|
||||||
|
entry = "src/canvas-card.tsx";
|
||||||
|
export = "CanvasCard";
|
||||||
|
};
|
||||||
|
}
|
||||||
Generated
+108
@@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"helpers": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1791886789,
|
||||||
|
"narHash": "sha256-7YF98v0AcxD1qkAdS+nL/aDtmTvcRzld9CB9AxY0qaA=",
|
||||||
|
"ref": "refs/tags/quixos-reachability/5657043450c46fc84e1a6d38c2f8919ba1e9d10c",
|
||||||
|
"rev": "5657043450c46fc84e1a6d38c2f8919ba1e9d10c",
|
||||||
|
"revCount": 78,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://repos.quixos.org/quixos-toolchain/quixos-nix-helpers.git"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"ref": "refs/tags/quixos-reachability/5657043450c46fc84e1a6d38c2f8919ba1e9d10c",
|
||||||
|
"rev": "5657043450c46fc84e1a6d38c2f8919ba1e9d10c",
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://repos.quixos.org/quixos-toolchain/quixos-nix-helpers.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1783776592,
|
||||||
|
"narHash": "sha256-UgCQzxeWI75XM8G+hPrPh+MKzEPjG3SpAj7dtqSbksA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e7a3ca8092b61ff85b6a45bf863ea2b2d6a661b3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1792963716,
|
||||||
|
"narHash": "sha256-MESSLO46ZHYtxVhlNpQfpiHi/A6WJEYDnczr+I3Wfb8=",
|
||||||
|
"ref": "refs/tags/quixos-reachability/d829d584af91326aacb8997459014c49def2f66e",
|
||||||
|
"rev": "d829d584af91326aacb8997459014c49def2f66e",
|
||||||
|
"revCount": 233,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://repos.quixos.org/quixos-toolchain/quixos-protocol.git"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"ref": "refs/tags/quixos-reachability/d829d584af91326aacb8997459014c49def2f66e",
|
||||||
|
"rev": "d829d584af91326aacb8997459014c49def2f66e",
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://repos.quixos.org/quixos-toolchain/quixos-protocol.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": [
|
||||||
|
"protocol",
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"helpers": "helpers",
|
||||||
|
"nixpkgs": [
|
||||||
|
"protocol",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"protocol": "protocol"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
inputs.protocol.url = "git+https://repos.quixos.org/quixos-toolchain/quixos-protocol.git?ref=refs/tags/quixos-reachability/d829d584af91326aacb8997459014c49def2f66e&rev=d829d584af91326aacb8997459014c49def2f66e";
|
||||||
|
inputs.nixpkgs.follows = "protocol/nixpkgs";
|
||||||
|
inputs.flake-utils.follows = "protocol/flake-utils";
|
||||||
|
inputs.helpers = {
|
||||||
|
url = "git+https://repos.quixos.org/quixos-toolchain/quixos-nix-helpers.git?ref=refs/tags/quixos-reachability/5657043450c46fc84e1a6d38c2f8919ba1e9d10c&rev=5657043450c46fc84e1a6d38c2f8919ba1e9d10c";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
helpers,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
camino = import (helpers + "/quixos-package-helpers.nix");
|
||||||
|
in
|
||||||
|
{
|
||||||
|
quixosPackages.checkedArtifacts =
|
||||||
|
context:
|
||||||
|
let
|
||||||
|
pkgs = camino.packageSet { inherit nixpkgs system context; };
|
||||||
|
dependencies =
|
||||||
|
if builtins.pathExists ./yarn-project.nix then
|
||||||
|
camino.mkCaminoYarnDependencies {
|
||||||
|
inherit pkgs;
|
||||||
|
src = ./.;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
in
|
||||||
|
camino.assembleCaminoPackage {
|
||||||
|
inherit pkgs context;
|
||||||
|
artifacts = [
|
||||||
|
(camino.mkCaminoTypeScriptPackage {
|
||||||
|
inherit pkgs context dependencies;
|
||||||
|
src = ./.;
|
||||||
|
entry = "src/server.ts";
|
||||||
|
entries.browser = "src/browser.ts";
|
||||||
|
})
|
||||||
|
(camino.mkCaminoReactPackage {
|
||||||
|
inherit pkgs context dependencies;
|
||||||
|
src = ./.;
|
||||||
|
modules = import ./components.nix;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
devShells.default = camino.mkCaminoYarnShell { inherit pkgs; };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "@quixos/web-studio-canvas-runtime",
|
||||||
|
"private": true,
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||||
|
import interface WebStudioFactory;
|
||||||
|
import interface WebStudioSearchable;
|
||||||
|
import interface StandaloneView;
|
||||||
|
import interface WebStudioCanvas;
|
||||||
|
import interface WebStudioCanvasPlacement;
|
||||||
|
import interface WebStudioPlaceable;
|
||||||
|
external atom WebStudioCanvas id "atom:org.quixos.web-studio:canvas";
|
||||||
|
external atom WebStudioCanvasPlacement id "atom:org.quixos.web-studio:canvas-placement";
|
||||||
|
type Position=record {x:double;y:double;};
|
||||||
|
type Size=record {width:double;height:double;};
|
||||||
|
type Layout=record {x:double;y:double;width:double;height:double;z:int32;};
|
||||||
|
type PlacementSeed=record {canvas:interface-ref<WebStudioCanvas>;subject:interface-ref<WebStudioPlaceable>;presentation:string;position:Position;size:Size;z:int32;};
|
||||||
|
package WebStudioCanvasRuntime id "package:org.quixos.web-studio:canvas-runtime" revision "package:org.quixos.web-studio:canvas-runtime@1" {
|
||||||
|
function createPlaced<value Input, object Result implements WebStudioPlaceable> id "studio:create-placed" : record {canvas:interface-ref<WebStudioCanvas>;seed:Input;presentation:string;layout:Layout;} -> atom-ref<WebStudioCanvasPlacement> execution transaction targets [JavaScript,server] requires {
|
||||||
|
interface factory id "factory" : WebStudioFactory<Input,Result> using [create.call];
|
||||||
|
interface canvas id "canvas" : WebStudioCanvas using [place.call] from input;
|
||||||
|
};
|
||||||
|
function createCanvas id "studio:create-canvas" : string -> atom-ref<WebStudioCanvas> execution transaction targets [JavaScript,server] requires {creation canvas id "canvas" : WebStudioCanvas input record {name:string;};};
|
||||||
|
function createRoot id "studio:create-root" : unit -> atom-ref<WebStudioCanvas> execution transaction targets [server] requires {creation canvas id "canvas" : WebStudioCanvas input record {name:string;};};
|
||||||
|
operation canPresent<object Subject> id "studio:can-present" : string -> bool mode call execution snapshot targets [JavaScript,server] receiver object Subject requires {reflection catalog id "catalog" [presentations];};
|
||||||
|
operation place id "studio:place" : record {subject:interface-ref<WebStudioPlaceable>;presentation:string;layout:Layout;} -> atom-ref<WebStudioCanvasPlacement> mode call execution transaction targets [JavaScript,server] receiver any requires {
|
||||||
|
interface subject id "subject" : WebStudioPlaceable using [canPresent.call] from input;
|
||||||
|
creation placement id "placement" : WebStudioCanvasPlacement input PlacementSeed;
|
||||||
|
};
|
||||||
|
operation createAndPlace id "studio:create-and-place" : record {name:string;presentation:string;layout:Layout;} -> atom-ref<WebStudioCanvasPlacement> mode call execution transaction targets [JavaScript,server] receiver any requires {
|
||||||
|
interface subject id "subject" : WebStudioPlaceable using [canPresent.call] from input;
|
||||||
|
creation canvas id "canvas" : WebStudioCanvas input record {name:string;};
|
||||||
|
creation placement id "placement" : WebStudioCanvasPlacement input PlacementSeed;
|
||||||
|
};
|
||||||
|
module CanvasCard id "component:studio:canvas-card" implements StandaloneView<interface WebStudioCanvas>.render;
|
||||||
|
query TitleInputs id "studio:title-inputs" root WebStudioCanvas document "queries/title-inputs.graphql" operation "TitleInputs" {replica;}
|
||||||
|
query TitleView id "studio:title-view" root WebStudioCanvas document "queries/title-view.graphql" operation "TitleView" {local from TitleInputs;watch;}
|
||||||
|
query CanvasIndexInputs id "studio:canvas-index-inputs" root workspace WebStudioCanvas document "queries/canvas-index-inputs.graphql" operation "CanvasIndexInputs" {replica;}
|
||||||
|
query CanvasIndex id "studio:canvas-index" root workspace WebStudioCanvas document "queries/canvas-index.graphql" operation "CanvasIndex" {local from CanvasIndexInputs;watch;}
|
||||||
|
query PlaceableInputs id "studio:placeable-inputs" root WebStudioPlaceable document "queries/placeable-inputs.graphql" operation "PlaceableInputs" {replica;}
|
||||||
|
query PlaceableView id "studio:placeable-view" root WebStudioPlaceable document "queries/placeable-view.graphql" operation "PlaceableView" {local from PlaceableInputs;watch;}
|
||||||
|
query PlacementInputs id "studio:placement-inputs" root WebStudioCanvasPlacement document "queries/placement-inputs.graphql" operation "PlacementInputs" {replica;}
|
||||||
|
query CanvasInputs id "studio:canvas-inputs" root WebStudioCanvas document "queries/canvas-inputs.graphql" operation "CanvasInputs" {replica;max rows 200;}
|
||||||
|
query CanvasView id "studio:canvas-view" root WebStudioCanvas document "queries/canvas-view.graphql" operation "CanvasView" {local from CanvasInputs;max rows 200;watch;}
|
||||||
|
query SearchInputs id "studio:search-inputs" root workspace WebStudioSearchable document "queries/search-inputs.graphql" operation "SearchInputs" {replica;}
|
||||||
|
query Search id "studio:search" root workspace WebStudioSearchable document "queries/search.graphql" operation "Search" {local from SearchInputs;watch;}
|
||||||
|
query LabelInputs id "studio:label-inputs" root workspace WebStudioSearchable document "queries/label-inputs.graphql" operation "LabelInputs" {replica;}
|
||||||
|
query Labels id "studio:labels" root workspace WebStudioSearchable document "queries/labels.graphql" operation "Labels" {local from LabelInputs;watch;}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query CanvasIndexInputs { root { objects(all: 100) { entries { node { _camino {ref} name } } } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query CanvasIndex { root { availableObjects(all: 100) { entries { node { _camino {ref} name } } } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query CanvasInputs { root { name placements(all: 200) { entries { key node { _camino {ref} position {x y} size {width height} z presentation subject { _camino {ref} } } } } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query CanvasView { root { name placements(all: 200) { entries { key node { _camino {ref} position {x y} size {width height} z presentation subject { _camino {ref} } } } } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query LabelInputs($refs: [QxRef_WebStudioSearchable!]!) { root { objects(all: 100, where: {_camino: {ref: {in: $refs}}}) { entries { node { _camino {ref} title } } } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query Labels($refs: [QxRef_WebStudioSearchable!]!) { root { objects(all: 100, where: {_camino: {ref: {in: $refs}}}) { entries { node { _camino {ref} title } } } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query PlaceableInputs { root { _camino { ref } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query PlaceableView { root { _camino { ref } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query PlacementInputs { root { _camino {ref} position {x y} size {width height} z presentation subject { _camino {ref} } canvas { _camino {ref} name } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query SearchInputs($text: String!, $after: Cursor) { root { objects(first: 30, after: $after, where: {or: [{title: {containsInsensitive: $text}}, {searchText: {containsInsensitive: $text}}]}, orderBy: {title: ASC}) { entries { node { _camino {ref} title } } pageInfo {hasNextPage endCursor} } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query Search($text: String!, $after: Cursor) { root { objects(first: 30, after: $after, where: {or: [{title: {containsInsensitive: $text}}, {searchText: {containsInsensitive: $text}}]}, orderBy: {title: ASC}) { entries { node { _camino {ref} title } } pageInfo {hasNextPage endCursor} } } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query TitleInputs { root { name } }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query TitleView { root { name } }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"backend": "execution",
|
||||||
|
"queryFrontends": ["react"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
quixos-lock version 1 {
|
||||||
|
quixos source { repository "https://gitea.internal.quixos.org/quixos/quixos.git"; commit "c5854ac7629ac10f984b745270bdd022e2eed236"; }
|
||||||
|
interface WebStudioFactory source { repository "https://repos.quixos.org/quixos-studio/interface-web-studio-factory.git"; commit "a4136d9bfd765db6b2de2188ef2caf341e0f7a61"; }
|
||||||
|
interface WebStudioSearchable source { repository "https://repos.quixos.org/quixos-studio/interface-web-studio-searchable.git"; commit "b51116e6d320fc4dcd79f0d067124adf6a8e919f"; }
|
||||||
|
interface StandaloneView source { repository "https://repos.quixos.org/quixos-studio/interface-react-standalone-view.git"; commit "67b00f7ff8df87a477e12c5668c42684d8fa1708"; }
|
||||||
|
interface WebStudioCanvas source { repository "https://repos.quixos.org/quixos-studio/interface-web-studio-canvas.git"; commit "fb076e2d0d48080f76b88b2ffa4edeb4c37a7342"; }
|
||||||
|
interface WebStudioCanvasPlacement source { repository "https://repos.quixos.org/quixos-studio/interface-web-studio-canvas-placement.git"; commit "8bee874e37700fc860f066f11946efc82a1f521d"; }
|
||||||
|
interface WebStudioPlaceable source { repository "https://repos.quixos.org/quixos-studio/interface-web-studio-placeable.git"; commit "a998ebd982f7b61946156a0fa7038bc1295c3afc"; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"modules": {
|
||||||
|
"CanvasCard": {
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"query": "TitleView",
|
||||||
|
"root": {
|
||||||
|
"from": "input",
|
||||||
|
"path": ["subject"]
|
||||||
|
},
|
||||||
|
"arguments": {
|
||||||
|
"record": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { createRegistry } from "./gen/qx.js";
|
||||||
|
import { handlers } from "./portable.js";
|
||||||
|
export const registry = createRegistry(handlers);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import type { Modules } from "./gen/client.js";
|
||||||
|
export const CanvasCard: Modules["CanvasCard"] = ({ input }) => <p>{input.body.root.name}</p>;
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import { QxReject, type ExactReference, type MutationKey } from "@quixos/camino-replica-core";
|
||||||
|
import { generic, type Contexts, type PortableImplementation } from "./gen/qx.js";
|
||||||
|
const position = (value: { readonly x: number; readonly y: number }) => {
|
||||||
|
if (!Number.isFinite(value.x) || !Number.isFinite(value.y)) throw new QxReject("INVALID_POSITION");
|
||||||
|
};
|
||||||
|
const size = (value: { readonly width: number; readonly height: number }) => {
|
||||||
|
if (!Number.isFinite(value.width) || !Number.isFinite(value.height) || value.width <= 0 || value.height <= 0)
|
||||||
|
throw new QxReject("INVALID_SIZE");
|
||||||
|
};
|
||||||
|
const canPresent = async ({
|
||||||
|
receiver,
|
||||||
|
input,
|
||||||
|
ports,
|
||||||
|
}: {
|
||||||
|
readonly receiver: ExactReference;
|
||||||
|
readonly input: string;
|
||||||
|
readonly ports: {
|
||||||
|
readonly catalog: {
|
||||||
|
presentations(): Promise<ReadonlyArray<{ readonly id: string; readonly atoms: readonly string[] }>>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
const presentations = await ports.catalog.presentations();
|
||||||
|
return presentations.some((p) => p.id === input && p.atoms.includes(receiver.expectation.id));
|
||||||
|
};
|
||||||
|
const place = async ({ receiver, input, ports }: Contexts["place"]) => {
|
||||||
|
position(input.layout);
|
||||||
|
size(input.layout);
|
||||||
|
if (!(await ports.subject["canPresent.call"]({ receiver: input.subject, input: input.presentation })))
|
||||||
|
throw new QxReject("INVALID_PRESENTATION");
|
||||||
|
return ports.placement.create(
|
||||||
|
{
|
||||||
|
canvas: { ...receiver, expectation: { kind: "interface", id: "interface:org.quixos.web-studio.canvas@1" } },
|
||||||
|
subject: input.subject,
|
||||||
|
presentation: input.presentation,
|
||||||
|
position: { x: input.layout.x, y: input.layout.y },
|
||||||
|
size: { width: input.layout.width, height: input.layout.height },
|
||||||
|
z: input.layout.z,
|
||||||
|
},
|
||||||
|
{ key: "placement" },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const createPlaced = async <Input>({
|
||||||
|
input,
|
||||||
|
ports,
|
||||||
|
}: {
|
||||||
|
input: {
|
||||||
|
seed: Input;
|
||||||
|
canvas: Contexts["place"]["receiver"];
|
||||||
|
presentation: string;
|
||||||
|
layout: Contexts["place"]["input"]["layout"];
|
||||||
|
};
|
||||||
|
ports: {
|
||||||
|
factory: { "create.call"(input: Input, key: MutationKey): Promise<ExactReference> };
|
||||||
|
canvas: {
|
||||||
|
"place.call"(
|
||||||
|
input: { receiver: ExactReference; input: Contexts["place"]["input"] },
|
||||||
|
key: MutationKey,
|
||||||
|
): Promise<Awaited<ReturnType<PortableImplementation["place"]>>>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
const subject = await ports.factory["create.call"](input.seed, { key: "subject" });
|
||||||
|
return ports.canvas["place.call"](
|
||||||
|
{
|
||||||
|
receiver: input.canvas,
|
||||||
|
input: {
|
||||||
|
subject: { ...subject, expectation: { kind: "interface", id: "interface:org.quixos.web-studio.placeable@1" } },
|
||||||
|
presentation: input.presentation,
|
||||||
|
layout: input.layout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ key: "placement" },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const handlers: Omit<PortableImplementation, "createRoot"> = {
|
||||||
|
...generic.canPresent(canPresent),
|
||||||
|
...generic.createPlaced(createPlaced),
|
||||||
|
createCanvas: ({ input, ports }) => ports.canvas.create({ name: input }, { key: "canvas" }),
|
||||||
|
place,
|
||||||
|
createAndPlace: async (context) => {
|
||||||
|
const subject = await context.ports.canvas.create({ name: context.input.name }, { key: "canvas" });
|
||||||
|
return place({
|
||||||
|
...context,
|
||||||
|
input: {
|
||||||
|
subject: { ...subject, expectation: { kind: "interface", id: "interface:org.quixos.web-studio.placeable@1" } },
|
||||||
|
presentation: context.input.presentation,
|
||||||
|
layout: context.input.layout,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { createRegistry } from "./gen/qx.js";
|
||||||
|
import { handlers } from "./portable.js";
|
||||||
|
// The workspace entry protocol owns stable birth identity and idempotency.
|
||||||
|
export const registry = createRegistry({
|
||||||
|
...handlers,
|
||||||
|
createRoot: ({ ports }) => ports.canvas.create({ name: "Workspace" }, { key: "canvas" }),
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"target": "ES2024",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user