@powerhousedao/renown-package 0.0.3 → 0.0.5

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.
Files changed (45) hide show
  1. package/dist/document-models/renown-credential/gen/document-model.js +97 -11
  2. package/dist/document-models/renown-credential/gen/manager/actions.d.ts +14 -2
  3. package/dist/document-models/renown-credential/gen/manager/creators.d.ts +5 -2
  4. package/dist/document-models/renown-credential/gen/manager/creators.js +4 -1
  5. package/dist/document-models/renown-credential/gen/manager/error.d.ts +45 -1
  6. package/dist/document-models/renown-credential/gen/manager/error.js +53 -1
  7. package/dist/document-models/renown-credential/gen/manager/object.d.ts +4 -1
  8. package/dist/document-models/renown-credential/gen/manager/object.js +10 -1
  9. package/dist/document-models/renown-credential/gen/manager/operations.d.ts +4 -1
  10. package/dist/document-models/renown-credential/gen/ph-factories.js +11 -5
  11. package/dist/document-models/renown-credential/gen/reducer.js +12 -0
  12. package/dist/document-models/renown-credential/gen/schema/types.d.ts +43 -12
  13. package/dist/document-models/renown-credential/gen/schema/zod.d.ts +5 -1
  14. package/dist/document-models/renown-credential/gen/schema/zod.js +48 -10
  15. package/dist/document-models/renown-credential/gen/utils.js +12 -6
  16. package/dist/document-models/renown-credential/index.d.ts +3 -0
  17. package/dist/document-models/renown-credential/src/reducers/manager.js +69 -15
  18. package/dist/document-models/renown-user/gen/object.d.ts +1 -1
  19. package/dist/document-models/renown-user/gen/profile/object.d.ts +1 -1
  20. package/dist/document-models/renown-user/gen/reducer.d.ts +1 -1
  21. package/dist/document-models/renown-user/gen/utils.d.ts +1 -1
  22. package/dist/editors/hooks/useRenownCredentialDocument.d.ts +3 -0
  23. package/dist/editors/hooks/useRenownCredentialDocument.js +8 -0
  24. package/dist/editors/index.d.ts +1 -0
  25. package/dist/editors/index.js +1 -0
  26. package/dist/editors/renown-credential-editor/editor.d.ts +3 -0
  27. package/dist/editors/renown-credential-editor/editor.js +115 -0
  28. package/dist/editors/renown-credential-editor/index.d.ts +2 -0
  29. package/dist/editors/renown-credential-editor/index.js +11 -0
  30. package/dist/powerhouse.manifest.json +4 -0
  31. package/dist/processors/index.d.ts +1 -0
  32. package/dist/processors/index.js +1 -0
  33. package/dist/processors/renown-credential/index.d.ts +9 -0
  34. package/dist/processors/renown-credential/index.js +129 -0
  35. package/dist/processors/renown-credential/migrations.d.ts +3 -0
  36. package/dist/processors/renown-credential/migrations.js +77 -0
  37. package/dist/processors/renown-credential/schema.d.ts +27 -0
  38. package/dist/processors/renown-credential/schema.js +1 -0
  39. package/dist/processors/renown-user/migrations.js +2 -2
  40. package/dist/style.css +107 -12
  41. package/dist/subgraphs/renown-credential/resolvers.js +39 -3
  42. package/dist/subgraphs/renown-credential/schema.js +63 -13
  43. package/dist/subgraphs/renown-read-model/resolvers.js +99 -76
  44. package/dist/subgraphs/renown-read-model/schema.js +48 -15
  45. package/package.json +31 -1
@@ -1,23 +1,77 @@
1
+ import { InvalidStatusPurposeError, MissingContextError, MissingTypeError, InvalidClaimsError, CredentialRevokedError, AlreadyRevokedError, } from "../../gen/manager/error.js";
1
2
  export const reducer = {
2
3
  initOperation(state, action, dispatch) {
3
- const { issuer, subject, jwt, audience, payload } = action.input;
4
- const credential = {
5
- issuer: issuer || null,
6
- subject: subject || null,
7
- jwt,
8
- revoked: false,
9
- audience: audience || null,
10
- payload: payload || null,
11
- };
12
- state = {
13
- ...state,
14
- ...credential,
4
+ // Validate context
5
+ const context = action.input.context && action.input.context.length > 0
6
+ ? action.input.context
7
+ : ["https://www.w3.org/2018/credentials/v1"];
8
+ if (!context.includes("https://www.w3.org/2018/credentials/v1")) {
9
+ throw new MissingContextError("Context must include https://www.w3.org/2018/credentials/v1");
10
+ }
11
+ // Validate type
12
+ const type = action.input.type && action.input.type.length > 0
13
+ ? action.input.type
14
+ : ["VerifiableCredential"];
15
+ if (!type.includes("VerifiableCredential")) {
16
+ throw new MissingTypeError("Type must include VerifiableCredential");
17
+ }
18
+ // Validate credentialSubject is valid JSON
19
+ try {
20
+ JSON.parse(action.input.credentialSubject);
21
+ }
22
+ catch (e) {
23
+ throw new InvalidClaimsError("Credential subject must be valid JSON");
24
+ }
25
+ state.context = context;
26
+ state.id = action.input.id || null;
27
+ state.type = type;
28
+ state.issuer = action.input.issuer;
29
+ state.issuanceDate = action.input.issuanceDate;
30
+ state.credentialSubject = action.input.credentialSubject;
31
+ state.expirationDate = action.input.expirationDate || null;
32
+ state.credentialStatus = null;
33
+ state.jwt = null;
34
+ state.revoked = false;
35
+ state.revokedAt = null;
36
+ state.revocationReason = null;
37
+ },
38
+ updateCredentialSubjectOperation(state, action, dispatch) {
39
+ if (state.revoked) {
40
+ throw new CredentialRevokedError("Cannot update a revoked credential");
41
+ }
42
+ // Validate credentialSubject is valid JSON
43
+ try {
44
+ JSON.parse(action.input.credentialSubject);
45
+ }
46
+ catch (e) {
47
+ throw new InvalidClaimsError("Credential subject must be valid JSON");
48
+ }
49
+ state.credentialSubject = action.input.credentialSubject;
50
+ // Clear JWT as credential content has changed
51
+ state.jwt = null;
52
+ },
53
+ setJwtOperation(state, action, dispatch) {
54
+ state.jwt = action.input.jwt;
55
+ },
56
+ setCredentialStatusOperation(state, action, dispatch) {
57
+ // Validate statusPurpose
58
+ if (action.input.statusPurpose !== "revocation" && action.input.statusPurpose !== "suspension") {
59
+ throw new InvalidStatusPurposeError("Status purpose must be 'revocation' or 'suspension'");
60
+ }
61
+ state.credentialStatus = {
62
+ id: action.input.statusId,
63
+ type: action.input.statusType,
64
+ statusPurpose: action.input.statusPurpose,
65
+ statusListIndex: action.input.statusListIndex,
66
+ statusListCredential: action.input.statusListCredential
15
67
  };
16
68
  },
17
69
  revokeOperation(state, action, dispatch) {
18
- const { jwt } = action.input;
70
+ if (state.revoked) {
71
+ throw new AlreadyRevokedError("Credential is already revoked");
72
+ }
19
73
  state.revoked = true;
20
- state.jwt = jwt || null;
21
- return state;
74
+ state.revokedAt = action.input.revokedAt;
75
+ state.revocationReason = action.input.reason || null;
22
76
  },
23
77
  };
@@ -1,5 +1,5 @@
1
1
  import { BaseDocumentClass, type SignalDispatch } from "document-model";
2
- import { RenownUserPHState } from "./ph-factories.js";
2
+ import { type RenownUserPHState } from "./ph-factories.js";
3
3
  import RenownUser_Profile from "./profile/object.js";
4
4
  export * from "./profile/object.js";
5
5
  interface RenownUser extends RenownUser_Profile {
@@ -1,5 +1,5 @@
1
1
  import { BaseDocumentClass } from "document-model";
2
- import { RenownUserPHState } from "../ph-factories.js";
2
+ import { type RenownUserPHState } from "../ph-factories.js";
3
3
  import { type SetUsernameInput, type SetEthAddressInput, type SetUserImageInput } from "../types.js";
4
4
  export default class RenownUser_Profile extends BaseDocumentClass<RenownUserPHState> {
5
5
  setUsername(input: SetUsernameInput): this;
@@ -1,4 +1,4 @@
1
1
  import { type StateReducer } from "document-model";
2
- import { RenownUserPHState } from "./ph-factories.js";
2
+ import { type RenownUserPHState } from "./ph-factories.js";
3
3
  export declare const stateReducer: StateReducer<RenownUserPHState>;
4
4
  export declare const reducer: import("document-model").Reducer<RenownUserPHState>;
@@ -1,6 +1,6 @@
1
1
  import { type CreateDocument, type CreateState, type LoadFromFile, type LoadFromInput } from "document-model";
2
2
  import { type RenownUserState, type RenownUserLocalState } from "./types.js";
3
- import { RenownUserPHState } from "./ph-factories.js";
3
+ import { type RenownUserPHState } from "./ph-factories.js";
4
4
  export declare const initialGlobalState: RenownUserState;
5
5
  export declare const initialLocalState: RenownUserLocalState;
6
6
  export declare const createState: CreateState<RenownUserPHState>;
@@ -0,0 +1,3 @@
1
+ import type { RenownCredentialDocument } from "../../document-models/renown-credential/index.js";
2
+ export declare function useRenownCredentialDocument(documentId: string | null | undefined): never[] | [RenownCredentialDocument, import("@powerhousedao/reactor-browser").DocumentDispatch<import("../../document-models/renown-credential/gen/actions.js").RenownCredentialManagerAction>];
3
+ export declare function useSelectedRenownCredentialDocument(): never[] | [RenownCredentialDocument, import("@powerhousedao/reactor-browser").DocumentDispatch<import("../../document-models/renown-credential/gen/actions.js").RenownCredentialManagerAction>];
@@ -0,0 +1,8 @@
1
+ import { useDocumentOfType, useSelectedDocumentId, } from "@powerhousedao/reactor-browser";
2
+ export function useRenownCredentialDocument(documentId) {
3
+ return useDocumentOfType(documentId, "powerhouse/renown-credential");
4
+ }
5
+ export function useSelectedRenownCredentialDocument() {
6
+ const selectedDocumentId = useSelectedDocumentId();
7
+ return useRenownCredentialDocument(selectedDocumentId);
8
+ }
@@ -1,2 +1,3 @@
1
1
  export {};
2
2
  export { module as RenownUserEditor } from "./renown-user-editor/index.js";
3
+ export { module as RenownCredentialEditor } from "./renown-credential-editor/index.js";
@@ -1 +1,2 @@
1
1
  export { module as RenownUserEditor } from "./renown-user-editor/index.js";
2
+ export { module as RenownCredentialEditor } from "./renown-credential-editor/index.js";
@@ -0,0 +1,3 @@
1
+ import type { EditorProps } from "document-model";
2
+ export type IProps = EditorProps;
3
+ export declare function Editor(props: IProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,115 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useSelectedDocument } from "@powerhousedao/reactor-browser";
3
+ import { useCallback, useState } from "react";
4
+ import { actions, } from "../../document-models/renown-credential/index.js";
5
+ import { Form, StringField, TextareaField, Button, } from "@powerhousedao/document-engineering";
6
+ export function Editor(props) {
7
+ const [document, dispatch] = useSelectedDocument();
8
+ if (!document) {
9
+ return _jsx("div", { children: "Loading..." });
10
+ }
11
+ const typedDocument = document;
12
+ // Local form state
13
+ const [isInitializing, setIsInitializing] = useState(false);
14
+ const [isEditingSubject, setIsEditingSubject] = useState(false);
15
+ const [isSettingJwt, setIsSettingJwt] = useState(false);
16
+ const [isSettingStatus, setIsSettingStatus] = useState(false);
17
+ const { state: { global }, } = typedDocument;
18
+ const { context, id: credentialId, type, issuer, issuanceDate, credentialSubject, expirationDate, credentialStatus, jwt, revoked, revokedAt, revocationReason, } = global;
19
+ const isInitialized = issuer && issuanceDate;
20
+ // Initialize credential
21
+ const handleInit = useCallback((values) => {
22
+ try {
23
+ const contextArray = values.context
24
+ ? values.context.split(",").map((s) => s.trim())
25
+ : undefined;
26
+ const typeArray = values.type
27
+ ? values.type.split(",").map((s) => s.trim())
28
+ : undefined;
29
+ dispatch(actions.init({
30
+ issuer: values.issuer,
31
+ issuanceDate: new Date().toISOString(),
32
+ credentialSubject: values.credentialSubject,
33
+ expirationDate: values.expirationDate || undefined,
34
+ context: contextArray,
35
+ type: typeArray,
36
+ id: values.id,
37
+ }));
38
+ setIsInitializing(false);
39
+ }
40
+ catch (error) {
41
+ console.error("Error initializing credential:", error);
42
+ }
43
+ }, [dispatch]);
44
+ // Update credential subject
45
+ const handleUpdateSubject = useCallback((newSubject) => {
46
+ try {
47
+ JSON.parse(newSubject); // Validate JSON
48
+ dispatch(actions.updateCredentialSubject({ credentialSubject: newSubject }));
49
+ setIsEditingSubject(false);
50
+ }
51
+ catch (error) {
52
+ console.error("Error updating credential subject:", error);
53
+ }
54
+ }, [dispatch]);
55
+ // Set JWT
56
+ const handleSetJwt = useCallback((newJwt) => {
57
+ dispatch(actions.setJwt({ jwt: newJwt }));
58
+ setIsSettingJwt(false);
59
+ }, [dispatch]);
60
+ // Set credential status
61
+ const handleSetStatus = useCallback((values) => {
62
+ dispatch(actions.setCredentialStatus(values));
63
+ setIsSettingStatus(false);
64
+ }, [dispatch]);
65
+ // Revoke credential
66
+ const handleRevoke = useCallback((reason) => {
67
+ if (window.confirm("Are you sure you want to revoke this credential?")) {
68
+ dispatch(actions.revoke({
69
+ revokedAt: new Date().toISOString(),
70
+ reason,
71
+ }));
72
+ }
73
+ }, [dispatch]);
74
+ return (_jsxs("div", { className: "html-defaults-container min-h-screen bg-gray-50", children: [_jsx("div", { className: "bg-white border-b border-gray-200", children: _jsx("div", { className: "max-w-6xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsx("div", { className: "py-8", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("h1", { className: "text-3xl font-bold text-gray-900", children: "Verifiable Credential" }), revoked && (_jsx("span", { className: "inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800", children: "Revoked" })), !isInitialized && (_jsx("span", { className: "inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-yellow-100 text-yellow-800", children: "Not Initialized" }))] }), issuer && (_jsxs("p", { className: "text-gray-600 mt-2 text-sm", children: ["Issued by: ", _jsx("span", { className: "font-mono", children: issuer })] }))] }), isInitialized && !revoked && (_jsx(Button, { color: "danger", onClick: () => {
75
+ const reason = window.prompt("Enter revocation reason (optional):");
76
+ if (reason !== null) {
77
+ handleRevoke(reason || undefined);
78
+ }
79
+ }, children: "Revoke Credential" }))] }) }) }) }), _jsx("div", { className: "max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8", children: _jsx("div", { className: "grid grid-cols-1 gap-8", children: !isInitialized ? (
80
+ /* Initialize Section */
81
+ _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsxs("div", { className: "px-6 py-5 bg-blue-50", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Initialize Credential" }), _jsx("p", { className: "text-sm text-gray-600 mt-1", children: "Create a new W3C Verifiable Credential" })] }), _jsx("div", { className: "p-6", children: _jsx(Form, { onSubmit: (e) => {
82
+ e.preventDefault();
83
+ const formData = new FormData(e.target);
84
+ handleInit({
85
+ issuer: formData.get("issuer"),
86
+ credentialSubject: formData.get("credentialSubject"),
87
+ expirationDate: formData.get("expirationDate"),
88
+ context: formData.get("context"),
89
+ type: formData.get("type"),
90
+ id: formData.get("id"),
91
+ });
92
+ }, children: _jsxs("div", { className: "space-y-6", children: [_jsx(StringField, { name: "issuer", label: "Issuer", required: true, placeholder: "did:example:issuer123", description: "DID or URL of the credential issuer" }), _jsx(TextareaField, { name: "credentialSubject", label: "Credential Subject (JSON)", required: true, placeholder: '{"id": "did:example:subject123", "name": "Alice"}', description: "JSON object containing the claims about the subject", rows: 4 }), _jsx(StringField, { name: "expirationDate", label: "Expiration Date (Optional)", placeholder: "2025-12-31T23:59:59Z", description: "ISO 8601 date when the credential expires" }), _jsx(StringField, { name: "context", label: "Context (Optional)", placeholder: "https://www.w3.org/2018/credentials/v1, https://example.com/contexts/v1", description: "Comma-separated list of context URLs (default: W3C VC context)" }), _jsx(StringField, { name: "type", label: "Type (Optional)", placeholder: "VerifiableCredential, ExampleCredential", description: "Comma-separated list of types (default: VerifiableCredential)" }), _jsx(StringField, { name: "id", label: "Credential ID (Optional)", placeholder: "urn:uuid:...", description: "Unique identifier for this credential" }), _jsx("div", { className: "flex justify-end pt-4", children: _jsx(Button, { type: "submit", children: "Initialize Credential" }) })] }) }) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Information" }) }), _jsxs("div", { className: "p-6", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Credential ID" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: credentialId || (_jsx("span", { className: "text-gray-400 italic", children: "Not set" })) })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Issuer" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: issuer })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Issuance Date" }), _jsx("p", { className: "text-sm text-gray-900", children: issuanceDate
93
+ ? new Date(issuanceDate).toLocaleString()
94
+ : "N/A" })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Expiration Date" }), _jsx("p", { className: "text-sm text-gray-900", children: expirationDate ? (new Date(expirationDate).toLocaleString()) : (_jsx("span", { className: "text-gray-400 italic", children: "No expiration" })) })] })] }), _jsxs("div", { className: "mt-6 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Context" }), _jsx("div", { className: "flex flex-wrap gap-2", children: context && context.map((ctx, i) => (_jsx("span", { className: "inline-block px-2 py-1 text-xs font-mono bg-blue-100 text-blue-800 rounded", children: ctx }, i))) })] }), _jsxs("div", { className: "mt-6 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: type && type.map((t, i) => (_jsx("span", { className: "inline-block px-2 py-1 text-xs font-mono bg-green-100 text-green-800 rounded", children: t }, i))) })] })] })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Subject" }), !revoked && !isEditingSubject && (_jsx(Button, { color: "light", onClick: () => setIsEditingSubject(true), children: "Edit Subject" }))] }) }), _jsx("div", { className: "p-6", children: isEditingSubject ? (_jsx(Form, { onSubmit: (e) => {
95
+ e.preventDefault();
96
+ const formData = new FormData(e.target);
97
+ handleUpdateSubject(formData.get("credentialSubject"));
98
+ }, children: _jsxs("div", { className: "space-y-4", children: [_jsx(TextareaField, { name: "credentialSubject", label: "Credential Subject (JSON)", defaultValue: credentialSubject || "", required: true, rows: 8, description: "JSON object containing the claims about the subject" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsEditingSubject(false), children: "Cancel" }), _jsx(Button, { type: "submit", children: "Update Subject" })] })] }) })) : (_jsx("pre", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200 overflow-auto text-sm", children: JSON.stringify(JSON.parse(credentialSubject || "{}"), null, 2) })) })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "JWT Representation" }), !isSettingJwt && (_jsx(Button, { color: "light", onClick: () => setIsSettingJwt(true), children: jwt ? "Update JWT" : "Set JWT" }))] }) }), _jsx("div", { className: "p-6", children: isSettingJwt ? (_jsx(Form, { onSubmit: (e) => {
99
+ e.preventDefault();
100
+ const formData = new FormData(e.target);
101
+ handleSetJwt(formData.get("jwt"));
102
+ }, children: _jsxs("div", { className: "space-y-4", children: [_jsx(TextareaField, { name: "jwt", label: "JWT Token", defaultValue: jwt || "", required: true, rows: 6, description: "Signed JWT representation of the credential" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsSettingJwt(false), children: "Cancel" }), _jsx(Button, { type: "submit", children: "Set JWT" })] })] }) })) : jwt ? (_jsx("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: _jsx("p", { className: "text-xs font-mono text-gray-900 break-all", children: jwt }) })) : (_jsx("p", { className: "text-gray-500 italic", children: "No JWT set" })) })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Status (StatusList2021)" }), !credentialStatus && !isSettingStatus && (_jsx(Button, { color: "light", onClick: () => setIsSettingStatus(true), children: "Set Status" }))] }) }), _jsx("div", { className: "p-6", children: isSettingStatus ? (_jsx(Form, { onSubmit: (e) => {
103
+ e.preventDefault();
104
+ const formData = new FormData(e.target);
105
+ handleSetStatus({
106
+ statusId: formData.get("statusId"),
107
+ statusType: formData.get("statusType"),
108
+ statusPurpose: formData.get("statusPurpose"),
109
+ statusListIndex: formData.get("statusListIndex"),
110
+ statusListCredential: formData.get("statusListCredential"),
111
+ });
112
+ }, children: _jsxs("div", { className: "space-y-4", children: [_jsx(StringField, { name: "statusId", label: "Status ID", required: true, placeholder: "https://example.com/status/1" }), _jsx(StringField, { name: "statusType", label: "Status Type", required: true, placeholder: "StatusList2021Entry" }), _jsx(StringField, { name: "statusPurpose", label: "Status Purpose", required: true, placeholder: "revocation", description: "Either 'revocation' or 'suspension'" }), _jsx(StringField, { name: "statusListIndex", label: "Status List Index", required: true, placeholder: "12345" }), _jsx(TextareaField, { name: "statusListCredential", label: "Status List Credential URL", required: true, placeholder: "https://example.com/status-lists/1", rows: 2 }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsSettingStatus(false), children: "Cancel" }), _jsx(Button, { type: "submit", children: "Set Status" })] })] }) })) : credentialStatus ? (_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Status ID" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: credentialStatus.id })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Type" }), _jsx("p", { className: "text-sm text-gray-900", children: credentialStatus.type })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Purpose" }), _jsx("p", { className: "text-sm text-gray-900", children: credentialStatus.statusPurpose })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "List Index" }), _jsx("p", { className: "text-sm text-gray-900", children: credentialStatus.statusListIndex })] }), _jsxs("div", { className: "col-span-2 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Status List Credential" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: credentialStatus.statusListCredential })] })] })) : (_jsx("p", { className: "text-gray-500 italic", children: "No credential status set" })) })] }), revoked && (_jsxs("div", { className: "bg-red-50 rounded-xl shadow-md border border-red-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-red-100", children: _jsx("h2", { className: "text-2xl font-bold text-red-900", children: "Revocation Information" }) }), _jsx("div", { className: "p-6", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "bg-white p-4 rounded-lg border border-red-200", children: [_jsx("label", { className: "block text-xs font-semibold text-red-600 uppercase tracking-wider mb-2", children: "Revoked At" }), _jsx("p", { className: "text-sm text-gray-900", children: revokedAt
113
+ ? new Date(revokedAt).toLocaleString()
114
+ : "N/A" })] }), revocationReason && (_jsxs("div", { className: "bg-white p-4 rounded-lg border border-red-200", children: [_jsx("label", { className: "block text-xs font-semibold text-red-600 uppercase tracking-wider mb-2", children: "Revocation Reason" }), _jsx("p", { className: "text-sm text-gray-900", children: revocationReason })] }))] }) })] }))] })) }) })] }));
115
+ }
@@ -0,0 +1,2 @@
1
+ import type { EditorModule } from "document-model";
2
+ export declare const module: EditorModule;
@@ -0,0 +1,11 @@
1
+ import { Editor } from "./editor.js";
2
+ export const module = {
3
+ Component: Editor,
4
+ documentTypes: ["powerhouse/renown-credential"],
5
+ config: {
6
+ id: "renown-credential-editor",
7
+ disableExternalControls: true,
8
+ documentToolbarEnabled: true,
9
+ showSwitchboardLink: true,
10
+ },
11
+ };
@@ -14,6 +14,10 @@
14
14
  {
15
15
  "id": "renown/credential",
16
16
  "name": "RenownCredential"
17
+ },
18
+ {
19
+ "id": "powerhouse/renown-credential",
20
+ "name": "RenownCredential"
17
21
  }
18
22
  ],
19
23
  "editors": [
@@ -1,4 +1,5 @@
1
1
  export {};
2
2
  export * as RenownUserProcessor from "./renown-user/index.js";
3
3
  export { renownUserProcessorFactory } from "./renown-user/factory.js";
4
+ export * as RenownCredentialProcessor from "./renown-credential/index.js";
4
5
  export * from "./factory.js";
@@ -1,3 +1,4 @@
1
1
  export * as RenownUserProcessor from "./renown-user/index.js";
2
2
  export { renownUserProcessorFactory } from "./renown-user/factory.js";
3
+ export * as RenownCredentialProcessor from "./renown-credential/index.js";
3
4
  export * from "./factory.js";
@@ -0,0 +1,9 @@
1
+ import { RelationalDbProcessor } from "document-drive/processors/relational";
2
+ import { type InternalTransmitterUpdate } from "document-drive/server/listener/transmitter/internal";
3
+ import { type DB } from "./schema.js";
4
+ export declare class RenownCredentialProcessor extends RelationalDbProcessor<DB> {
5
+ static getNamespace(driveId: string): string;
6
+ initAndUpgrade(): Promise<void>;
7
+ onStrands(strands: InternalTransmitterUpdate[]): Promise<void>;
8
+ onDisconnect(): Promise<void>;
9
+ }
@@ -0,0 +1,129 @@
1
+ import { RelationalDbProcessor } from "document-drive/processors/relational";
2
+ import { up } from "./migrations.js";
3
+ export class RenownCredentialProcessor extends RelationalDbProcessor {
4
+ static getNamespace(driveId) {
5
+ // Default namespace: `${this.name}_${driveId.replaceAll("-", "_")}`
6
+ return super.getNamespace(driveId);
7
+ }
8
+ async initAndUpgrade() {
9
+ await up(this.relationalDb);
10
+ }
11
+ async onStrands(strands) {
12
+ if (strands.length === 0) {
13
+ return;
14
+ }
15
+ for (const strand of strands) {
16
+ if (strand.operations.length === 0) {
17
+ continue;
18
+ }
19
+ const documentId = strand.documentId;
20
+ // Ensure the Credential exists in the database
21
+ const existingCredential = await this.relationalDb
22
+ .selectFrom("renown_credential")
23
+ .select(["document_id"])
24
+ .where("document_id", "=", documentId)
25
+ .executeTakeFirst();
26
+ // Process each operation
27
+ for (const operation of strand.operations) {
28
+ switch (operation.action.type) {
29
+ case "INIT": {
30
+ const input = operation.action.input;
31
+ if (input && !existingCredential) {
32
+ await this.relationalDb
33
+ .insertInto("renown_credential")
34
+ .values({
35
+ document_id: documentId,
36
+ context: JSON.stringify(input.context || ["https://www.w3.org/2018/credentials/v1"]),
37
+ credential_id: input.id || null,
38
+ type: JSON.stringify(input.type || ["VerifiableCredential"]),
39
+ issuer: input.issuer,
40
+ issuance_date: new Date(input.issuanceDate),
41
+ credential_subject: input.credentialSubject,
42
+ expiration_date: input.expirationDate
43
+ ? new Date(input.expirationDate)
44
+ : null,
45
+ credential_status_id: null,
46
+ credential_status_type: null,
47
+ credential_status_purpose: null,
48
+ credential_status_list_index: null,
49
+ credential_status_list_credential: null,
50
+ jwt: null,
51
+ revoked: false,
52
+ revoked_at: null,
53
+ revocation_reason: null,
54
+ created_at: new Date(),
55
+ updated_at: new Date(),
56
+ })
57
+ .execute();
58
+ }
59
+ break;
60
+ }
61
+ case "UPDATE_CREDENTIAL_SUBJECT": {
62
+ const input = operation.action.input;
63
+ if (input && existingCredential) {
64
+ await this.relationalDb
65
+ .updateTable("renown_credential")
66
+ .set({
67
+ credential_subject: input.credentialSubject,
68
+ jwt: null, // Clear JWT when content changes
69
+ updated_at: new Date(),
70
+ })
71
+ .where("document_id", "=", documentId)
72
+ .execute();
73
+ }
74
+ break;
75
+ }
76
+ case "SET_JWT": {
77
+ const input = operation.action.input;
78
+ if (input && existingCredential) {
79
+ await this.relationalDb
80
+ .updateTable("renown_credential")
81
+ .set({
82
+ jwt: input.jwt,
83
+ updated_at: new Date(),
84
+ })
85
+ .where("document_id", "=", documentId)
86
+ .execute();
87
+ }
88
+ break;
89
+ }
90
+ case "SET_CREDENTIAL_STATUS": {
91
+ const input = operation.action.input;
92
+ if (input && existingCredential) {
93
+ await this.relationalDb
94
+ .updateTable("renown_credential")
95
+ .set({
96
+ credential_status_id: input.statusId,
97
+ credential_status_type: input.statusType,
98
+ credential_status_purpose: input.statusPurpose,
99
+ credential_status_list_index: input.statusListIndex,
100
+ credential_status_list_credential: input.statusListCredential,
101
+ updated_at: new Date(),
102
+ })
103
+ .where("document_id", "=", documentId)
104
+ .execute();
105
+ }
106
+ break;
107
+ }
108
+ case "REVOKE": {
109
+ const input = operation.action.input;
110
+ if (input && existingCredential) {
111
+ await this.relationalDb
112
+ .updateTable("renown_credential")
113
+ .set({
114
+ revoked: true,
115
+ revoked_at: new Date(input.revokedAt),
116
+ revocation_reason: input.reason || null,
117
+ updated_at: new Date(),
118
+ })
119
+ .where("document_id", "=", documentId)
120
+ .execute();
121
+ }
122
+ break;
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ async onDisconnect() { }
129
+ }
@@ -0,0 +1,3 @@
1
+ import { type IRelationalDb } from "document-drive/processors/types";
2
+ export declare function up(db: IRelationalDb<any>): Promise<void>;
3
+ export declare function down(db: IRelationalDb<any>): Promise<void>;
@@ -0,0 +1,77 @@
1
+ export async function up(db) {
2
+ await down(db);
3
+ // Create renown_credential table
4
+ await db.schema
5
+ .createTable("renown_credential")
6
+ .addColumn("document_id", "varchar(255)")
7
+ .addColumn("context", "text") // JSON array
8
+ .addColumn("credential_id", "varchar(255)")
9
+ .addColumn("type", "text") // JSON array
10
+ .addColumn("issuer", "varchar(255)", (col) => col.notNull())
11
+ .addColumn("issuance_date", "timestamp", (col) => col.notNull())
12
+ .addColumn("credential_subject", "text", (col) => col.notNull()) // JSON object
13
+ .addColumn("expiration_date", "timestamp")
14
+ .addColumn("credential_status_id", "varchar(255)")
15
+ .addColumn("credential_status_type", "varchar(255)")
16
+ .addColumn("credential_status_purpose", "varchar(255)")
17
+ .addColumn("credential_status_list_index", "varchar(255)")
18
+ .addColumn("credential_status_list_credential", "text")
19
+ .addColumn("jwt", "text")
20
+ .addColumn("revoked", "boolean", (col) => col.notNull().defaultTo(false))
21
+ .addColumn("revoked_at", "timestamp")
22
+ .addColumn("revocation_reason", "text")
23
+ .addColumn("created_at", "timestamp", (col) => col.defaultTo(db.fn("now")))
24
+ .addColumn("updated_at", "timestamp", (col) => col.defaultTo(db.fn("now")))
25
+ .addPrimaryKeyConstraint("renown_credential_pkey", ["document_id"])
26
+ .ifNotExists()
27
+ .execute();
28
+ // Create index on credential_id for faster lookups
29
+ await db.schema
30
+ .createIndex("idx_renown_credential_credential_id")
31
+ .on("renown_credential")
32
+ .column("credential_id")
33
+ .ifNotExists()
34
+ .execute();
35
+ // Create index on issuer for faster lookups
36
+ await db.schema
37
+ .createIndex("idx_renown_credential_issuer")
38
+ .on("renown_credential")
39
+ .column("issuer")
40
+ .ifNotExists()
41
+ .execute();
42
+ // Create index on credential_subject for faster lookups (using GIN for JSONB-like searches)
43
+ await db.schema
44
+ .createIndex("idx_renown_credential_subject")
45
+ .on("renown_credential")
46
+ .column("credential_subject")
47
+ .ifNotExists()
48
+ .execute();
49
+ // Create index on revoked for faster validity checks
50
+ await db.schema
51
+ .createIndex("idx_renown_credential_revoked")
52
+ .on("renown_credential")
53
+ .column("revoked")
54
+ .ifNotExists()
55
+ .execute();
56
+ }
57
+ export async function down(db) {
58
+ // Drop renown_credential indexes
59
+ await db.schema
60
+ .dropIndex("idx_renown_credential_revoked")
61
+ .ifExists()
62
+ .execute();
63
+ await db.schema
64
+ .dropIndex("idx_renown_credential_subject")
65
+ .ifExists()
66
+ .execute();
67
+ await db.schema
68
+ .dropIndex("idx_renown_credential_issuer")
69
+ .ifExists()
70
+ .execute();
71
+ await db.schema
72
+ .dropIndex("idx_renown_credential_credential_id")
73
+ .ifExists()
74
+ .execute();
75
+ // Drop renown_credential table
76
+ await db.schema.dropTable("renown_credential").ifExists().execute();
77
+ }
@@ -0,0 +1,27 @@
1
+ import type { ColumnType } from "kysely";
2
+ export type Generated<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;
3
+ export type Timestamp = ColumnType<Date, Date | string, Date | string>;
4
+ export interface RenownCredential {
5
+ document_id: string;
6
+ context: string;
7
+ credential_id: string | null;
8
+ type: string;
9
+ issuer: string;
10
+ issuance_date: Timestamp;
11
+ credential_subject: string;
12
+ expiration_date: Timestamp | null;
13
+ credential_status_id: string | null;
14
+ credential_status_type: string | null;
15
+ credential_status_purpose: string | null;
16
+ credential_status_list_index: string | null;
17
+ credential_status_list_credential: string | null;
18
+ jwt: string | null;
19
+ revoked: boolean;
20
+ revoked_at: Timestamp | null;
21
+ revocation_reason: string | null;
22
+ created_at: Generated<Timestamp | null>;
23
+ updated_at: Generated<Timestamp | null>;
24
+ }
25
+ export interface DB {
26
+ renown_credential: RenownCredential;
27
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -28,9 +28,9 @@ export async function up(db) {
28
28
  .execute();
29
29
  }
30
30
  export async function down(db) {
31
- // Drop indexes
31
+ // Drop renown_user indexes
32
32
  await db.schema.dropIndex("idx_renown_user_eth_address").ifExists().execute();
33
33
  await db.schema.dropIndex("idx_renown_user_username").ifExists().execute();
34
- // Drop tables
34
+ // Drop renown_user table
35
35
  await db.schema.dropTable("renown_user").ifExists().execute();
36
36
  }