Merge pull request #5411 from urbit/hm/better-package-targets

npm: change build tool for wider distribution
This commit is contained in:
Hunter Miller 2021-11-23 17:01:55 -06:00 committed by GitHub
commit 2f19601d7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 92443 additions and 50919 deletions

View File

@ -4,4 +4,5 @@ bin/
.vscode/
.husky/
*.config.js
*.config.ts
*.config.ts
package.json

27529
pkg/grid/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,8 +22,8 @@
"@radix-ui/react-toggle": "^0.0.10",
"@tlon/sigil-js": "^1.4.4",
"@types/lodash": "^4.14.172",
"@urbit/api": "^2.0.0",
"@urbit/http-api": "^2.0.0",
"@urbit/api": "^2.1.0",
"@urbit/http-api": "^2.1.0",
"big-integer": "^1.6.48",
"classnames": "^2.3.1",
"clipboard-copy": "^4.0.1",

View File

@ -1,8 +1,7 @@
import { chadIsRunning, Treaty } from '@urbit/api';
import { chadIsRunning, Treaty, Vat } from '@urbit/api';
import clipboardCopy from 'clipboard-copy';
import React, { FC, useCallback, useState } from 'react';
import cn from 'classnames';
import { Vat } from '@urbit/api/hood';
import { Button, PillButton } from './Button';
import { Dialog, DialogClose, DialogContent, DialogTrigger } from './Dialog';
import { DocketHeader } from './DocketHeader';
@ -137,19 +136,19 @@ export const AppInfo: FC<AppInfoProps> = ({ docket, vat, className }) => {
</div>
</DocketHeader>
<div className="space-y-6">
{vat ? (
<>
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
<VatMeta vat={vat} />
</>
) : null}
{!treaty ? null : (
<>
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
<TreatyMeta treaty={treaty} />
</>
)}
</div>
{vat ? (
<>
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
<VatMeta vat={vat} />
</>
) : null}
{!treaty ? null : (
<>
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
<TreatyMeta treaty={treaty} />
</>
)}
</div>
</div>
);
};

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Docket } from '@urbit/api/docket';
import { Docket } from '@urbit/api';
import cn from 'classnames';
import { useTileColor } from '../tiles/useTileColor';

View File

@ -7,7 +7,13 @@ type ShipNameProps = {
export const ShipName = ({ name, ...props }: ShipNameProps) => {
const separator = /([_^-])/;
const parts = cite(name).replace('~', '').split(separator);
const citedName = cite(name);
if (!citedName) {
return null;
}
const parts = citedName.replace('~', '').split(separator);
const first = parts.shift();
return (

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Vat } from '@urbit/api/hood';
import { Vat } from '@urbit/api';
import { Attribute } from './Attribute';

View File

@ -3,7 +3,7 @@ import classNames from 'classnames';
import clipboardCopy from 'clipboard-copy';
import React, { HTMLAttributes, useCallback, useState } from 'react';
import { Link, Route, useHistory } from 'react-router-dom';
import { Vat } from '@urbit/api/hood';
import { Vat } from '@urbit/api';
import { Adjust } from '../components/icons/Adjust';
import { useVat } from '../state/kiln';
import { disableDefault, handleDropdownLink } from '../state/util';

View File

@ -1,6 +1,6 @@
import { pick } from 'lodash';
import React, { useCallback } from 'react';
import { kilnBump } from '@urbit/api/hood';
import { kilnBump } from '@urbit/api';
import { AppList } from '../../components/AppList';
import { Button } from '../../components/Button';
import { Dialog, DialogClose, DialogContent, DialogTrigger } from '../../components/Dialog';

View File

@ -1,4 +1,4 @@
import { setMentions } from '@urbit/api/dist';
import { setMentions } from '@urbit/api';
import React from 'react';
import { Setting } from '../../components/Setting';
import { pokeOptimisticallyN } from '../../state/base';

View File

@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
import {
BigIntOrderedMap,
makePatDa,
decToUd,
unixToDa,
@ -13,7 +14,6 @@ import {
NotificationGraphConfig,
archiveAll
} from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
/* eslint-disable-next-line camelcase */
import { unstable_batchedUpdates } from 'react-dom';
import produce from 'immer';

View File

@ -1,5 +1,13 @@
import { getVats, Vats, scryLag, getBlockers, Vat, kilnInstall } from '@urbit/api';
import { kilnPause, kilnResume } from '@urbit/api/hood';
import {
getVats,
Vats,
scryLag,
getBlockers,
Vat,
kilnInstall,
kilnPause,
kilnResume
} from '@urbit/api';
import create from 'zustand';
import produce from 'immer';
import { useCallback } from 'react';

View File

@ -5,7 +5,7 @@ import {
putEntry as doPutEntry,
getDeskSettings,
DeskData
} from '@urbit/api/settings';
} from '@urbit/api';
import _ from 'lodash';
import {
BaseState,

View File

@ -1,4 +1,4 @@
import { Docket, DocketHref, Treaty } from '@urbit/api/docket';
import { Docket, DocketHref, Treaty } from '@urbit/api';
import { hsla, parseToHsla } from 'color2k';
import _ from 'lodash';

View File

@ -73,7 +73,7 @@ module.exports = {
]
}
},
exclude: /node_modules\/(?!(@tlon\/indigo-dark|@tlon\/indigo-light|@tlon\/indigo-react)\/).*/
exclude: /node_modules\/(?!(@tlon\/indigo-dark|@tlon\/indigo-light|@tlon\/indigo-react|@urbit\/api)\/).*/
},
{
test: /\.css$/i,

View File

@ -30,7 +30,7 @@ module.exports = {
]
}
},
exclude: /node_modules\/(?!(@tlon\/indigo-dark|@tlon\/indigo-light|@tlon\/indigo-react)\/).*/
exclude: /node_modules\/(?!(@tlon\/indigo-dark|@tlon\/indigo-light|@tlon\/indigo-react|@urbit\/api)\/).*/
},
{
test: /\.css$/i,

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,8 @@
"@tlon/indigo-light": "^1.0.7",
"@tlon/indigo-react": "^1.2.23",
"@tlon/sigil-js": "^1.4.3",
"@urbit/api": "^2.0.0",
"@urbit/http-api": "^2.0.0",
"@urbit/api": "^2.1.0",
"@urbit/http-api": "^2.1.0",
"any-ascii": "^0.1.7",
"aws-sdk": "^2.830.0",
"big-integer": "^1.6.48",

View File

@ -1,5 +1,4 @@
import { Content, GraphNode, unixToDa } from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import { BigIntOrderedMap, Content, GraphNode, unixToDa } from '@urbit/api';
import bigInt, { BigInteger } from 'big-integer';
export const makeComment = (

View File

@ -1,5 +1,4 @@
import { deSig, Path, PatpNoSig } from '@urbit/api';
import { Group, Resource, roleTags, RoleTags } from '@urbit/api/groups';
import { deSig, Path, PatpNoSig, Group, Resource, roleTags, RoleTags } from '@urbit/api';
import _ from 'lodash';
export function roleForShip(

View File

@ -1,5 +1,4 @@
import { Content, GraphNode, Post, TextContent } from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import { BigIntOrderedMap, Content, GraphNode, Post, TextContent } from '@urbit/api';
import bigInt, { BigInteger } from 'big-integer';
import { buntPost } from '~/logic/lib/post';
import { unixToDa } from '~/logic/lib/util';

View File

@ -1,9 +1,4 @@
import { GraphNode } from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import BigIntArrayOrderedMap, {
arrToString,
stringToArr
} from '@urbit/api/lib/BigIntArrayOrderedMap';
import { arrToString, stringToArr, BigIntOrderedMap, BigIntArrayOrderedMap, GraphNode } from '@urbit/api';
import bigInt, { BigInteger } from 'big-integer';
import produce from 'immer';
import _ from 'lodash';

View File

@ -1,11 +1,9 @@
import { Enc } from '@urbit/api';
import {
Enc,
Group,
GroupPolicy, GroupUpdate,
InvitePolicy, InvitePolicyDiff, OpenPolicy, OpenPolicyDiff, Tags
} from '@urbit/api/groups';
} from '@urbit/api';
import _ from 'lodash';
import { Cage } from '~/types/cage';
import { resourceAsPath } from '../lib/util';

View File

@ -1,11 +1,11 @@
import {
BigIntOrderedMap,
HarkPlace,
Timebox,
HarkStats,
harkBinToId,
makePatDa
} from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import _ from 'lodash';
import { compose } from 'lodash/fp';
import { BaseState } from '../state/base';

View File

@ -1,4 +1,4 @@
import { InviteUpdate } from '@urbit/api/invite';
import { InviteUpdate } from '@urbit/api';
import _ from 'lodash';
import { BaseState } from '../state/base';
import { InviteState as State } from '../state/invite';

View File

@ -1,4 +1,4 @@
import { MetadataUpdate, Associations, ResourceAssociations } from '@urbit/api/metadata';
import { MetadataUpdate, Associations, ResourceAssociations } from '@urbit/api';
import _ from 'lodash';
import { Cage } from '~/types/cage';
import { BaseState } from '../state/base';

View File

@ -1,4 +1,4 @@
import { SettingsUpdate } from '@urbit/api/settings';
import { SettingsUpdate } from '@urbit/api';
import _ from 'lodash';
import { SettingsState as State } from '~/logic/state/settings';
import { BaseState } from '../state/base';

View File

@ -1,12 +1,12 @@
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import { patp2dec } from 'urbit-ob';
import shallow from 'zustand/shallow';
import { Association, deSig, GraphNode, Graphs, FlatGraphs, resourceFromPath, ThreadGraphs, getGraph, getShallowChildren, setScreen } from '@urbit/api';
import {
Association, BigIntOrderedMap, deSig, GraphNode, Graphs, FlatGraphs, resourceFromPath, ThreadGraphs, getGraph, getShallowChildren, setScreen,
addDmMessage, addPost, Content, getDeepOlderThan, getFirstborn, getNewest, getNode, getOlderSiblings, getYoungerSiblings, markPending, Post, addNode, GraphNodePoke
} from '@urbit/api';
import { useCallback } from 'react';
import { createState, createSubscription, reduceStateN, pokeOptimisticallyN } from './base';
import airlock from '~/logic/api';
import { addDmMessage, addPost, Content, getDeepOlderThan, getFirstborn, getNewest, getNode, getOlderSiblings, getYoungerSiblings, markPending, Post, addNode, GraphNodePoke } from '@urbit/api/graph';
import { GraphReducer, reduceDm } from '../reducers/graph-update';
import _ from 'lodash';
import { clone } from '../lib/util';

View File

@ -1,5 +1,6 @@
import {
archive,
BigIntOrderedMap,
HarkBin,
markCountAsRead,
NotificationGraphConfig,
@ -14,7 +15,6 @@ import {
import { Poke } from '@urbit/http-api';
import { patp2dec } from 'urbit-ob';
import _ from 'lodash';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import api from '~/logic/api';
import { useCallback, useMemo } from 'react';

View File

@ -1,4 +1,4 @@
import { Association, Associations, MetadataUpdatePreview } from '@urbit/api/metadata';
import { Association, Associations, MetadataUpdatePreview } from '@urbit/api';
import _ from 'lodash';
import { useCallback, useEffect, useState } from 'react';
import {

View File

@ -16,8 +16,7 @@ import {
import { useCallback } from 'react';
import { reduceUpdate } from '../reducers/settings-update';
import airlock from '~/logic/api';
import { getDeskSettings, Value } from '@urbit/api';
import { putEntry } from '@urbit/api/settings';
import { getDeskSettings, putEntry, Value } from '@urbit/api';
export interface ShortcutMapping {
cycleForward: string;

View File

@ -3,7 +3,7 @@ import { Meta, Story } from '@storybook/react';
import { Box } from '@tlon/indigo-react';
import { InviteItem, InviteItemProps } from '~/views/components/Invite';
import { JoinProgress } from '@urbit/api/groups';
import { JoinProgress } from '@urbit/api';
export default {
title: 'Notifications/Invite',

View File

@ -4,8 +4,7 @@ import { withDesign } from 'storybook-addon-designs';
import { Col, Row } from '@tlon/indigo-react';
import { LinkBlockItem } from '~/views/apps/links/components/LinkBlockItem';
import { createPost, GraphNode } from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import { BigIntOrderedMap, createPost, GraphNode } from '@urbit/api';
export default {
title: 'Collections/BlockItem',

View File

@ -4,8 +4,7 @@ import { withDesign } from 'storybook-addon-designs';
import { Box } from '@tlon/indigo-react';
import { LinkDetail } from '~/views/apps/links/components/LinkDetail';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import { GraphNode } from '@urbit/api';
import { BigIntOrderedMap, GraphNode } from '@urbit/api';
import useMetadataState from '~/logic/state/metadata';
import { makeComment } from '~/logic/lib/fixtures';

View File

@ -1,5 +1,4 @@
import { ContactUpdate, GroupUpdate, InviteUpdate, MetadataUpdate } from '@urbit/api';
import { SettingsUpdate } from '@urbit/api/settings';
import { ContactUpdate, GroupUpdate, InviteUpdate, MetadataUpdate, SettingsUpdate } from '@urbit/api';
import { ConnectionStatus } from './connection';
import { LaunchUpdate, WeatherState } from './launch-update';
import { LocalUpdate } from './local-update';

View File

@ -1,5 +1,4 @@
import { Content, createPost, fetchIsAllowed, Post, removePosts, deSig } from '@urbit/api';
import { Association } from '@urbit/api/metadata';
import { Association, Content, createPost, fetchIsAllowed, Post, removePosts, deSig } from '@urbit/api';
import { BigInteger } from 'big-integer';
import React, {
ReactElement, useCallback,

View File

@ -30,8 +30,7 @@ import Tiles from './components/tiles';
import Tile from './components/tiles/tile';
import { Invite } from './components/Invite';
import './css/custom.css';
import { join } from '@urbit/api/groups';
import { joinGraph } from '@urbit/api/graph';
import { join, joinGraph } from '@urbit/api';
import airlock from '~/logic/api';
const ScrollbarLessBox = styled(Box)`

View File

@ -1,6 +1,5 @@
import { Box, Center, Col, LoadingSpinner, Text } from '@tlon/indigo-react';
import { deSig, Group } from '@urbit/api';
import { Association } from '@urbit/api/metadata';
import { Association, deSig, Group } from '@urbit/api';
import bigInt from 'big-integer';
import React, { useEffect } from 'react';
import { Link, Route, Switch, useLocation } from 'react-router-dom';

View File

@ -1,12 +1,11 @@
import { Col, Row, Text } from '@tlon/indigo-react';
import { Association, Graph, GraphNode, markEachAsRead } from '@urbit/api';
import { Association, BigIntOrderedMap, Graph, GraphNode, markEachAsRead } from '@urbit/api';
import React, { useCallback, useState, useMemo, useEffect } from 'react';
import _ from 'lodash';
import { useResize } from '~/logic/lib/useResize';
import { LinkBlockItem } from './LinkBlockItem';
import { LinkBlockInput } from './LinkBlockInput';
import useLocalState from '~/logic/state/local';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import bigInt from 'big-integer';
import airlock from '~/logic/api';
import useHarkState, { selHarkGraph } from '~/logic/state/hark';

View File

@ -1,7 +1,7 @@
import { Box, Center, Col, Text } from '@tlon/indigo-react';
import React from 'react';
import useHarkState, { HarkState } from '~/logic/state/hark';
import { harkBinToId, HarkLid, Timebox } from '../../../../../npm/api/dist';
import { harkBinToId, HarkLid, Timebox } from '@urbit/api';
import { Notification } from './notification';
const unseenLid = { unseen: null };

View File

@ -3,7 +3,7 @@ import { Box, Row, Text } from '@tlon/indigo-react';
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
import Author from '~/views/components/Author';
import { useHistory } from 'react-router';
import { acceptDm, declineDm } from '@urbit/api/graph';
import { acceptDm, declineDm } from '@urbit/api';
import airlock from '~/logic/api';
export function PendingDm(props: { ship: string; }) {

View File

@ -1,6 +1,5 @@
import { Box, Col, Icon, Image, Row, Text } from '@tlon/indigo-react';
import { Group } from '@urbit/api';
import { GraphNode } from '@urbit/api/graph';
import { Group, GraphNode } from '@urbit/api';
import React from 'react';
import ReactMarkdown from 'react-markdown';
import { Link } from 'react-router-dom';

View File

@ -1,5 +1,4 @@
import { addNodes, Association } from '@urbit/api';
import { Graph } from '@urbit/api/graph';
import { addNodes, Association, Graph } from '@urbit/api';
import { FormikHelpers } from 'formik';
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';

View File

@ -9,7 +9,7 @@ import {
import { useField } from 'formik';
import React, { FormEvent, useState, useEffect } from 'react';
import { hexToUx } from '~/logic/lib/util';
import { uxToHex } from '@urbit/api/dist';
import { uxToHex } from '@urbit/api';
export type ColorInputProps = Parameters<typeof Col>[0] & {
id: string;

View File

@ -1,6 +1,5 @@
import { Action, Box, Col, Icon, Row, Text } from '@tlon/indigo-react';
import { Group, removePosts } from '@urbit/api';
import { GraphNode } from '@urbit/api/graph';
import { GraphNode, Group, removePosts } from '@urbit/api';
import bigInt from 'big-integer';
import React, { useCallback, useEffect, useRef } from 'react';
import { roleForShip } from '~/logic/lib/group';

View File

@ -6,8 +6,7 @@ import {
ErrorLabel, Icon, Label,
Row, Text
} from '@tlon/indigo-react';
import { OpenPolicy } from '@urbit/api';
import { Association } from '@urbit/api/metadata';
import { Association, OpenPolicy } from '@urbit/api';
import { FieldArray, useFormikContext } from 'formik';
import _ from 'lodash';
import React, { ReactElement, useMemo, useState } from 'react';

View File

@ -1,5 +1,4 @@
import { JoinRequest } from '@urbit/api';
import { Invite } from '@urbit/api/invite';
import { Invite, JoinRequest } from '@urbit/api';
import React from 'react';
import { usePreview } from '~/logic/state/metadata';
import { GroupInvite } from './Group';

View File

@ -1,9 +1,7 @@
import { BigInteger } from 'big-integer';
import React from 'react';
import VirtualScroller, { VirtualScrollerProps } from './VirtualScroller';
import { arrToString } from '@urbit/api/lib/BigIntArrayOrderedMap';
import { FlatGraphNode } from '@urbit/api';
import { arrToString, FlatGraphNode } from '@urbit/api';
type ThreadScrollerProps = Omit<
VirtualScrollerProps<BigInteger[], FlatGraphNode>,

View File

@ -1,6 +1,5 @@
import { Box, Center, Col, Text } from '@tlon/indigo-react';
import { joinGraph } from '@urbit/api/graph';
import { Association, GraphConfig } from '@urbit/api/metadata';
import { Association, GraphConfig, joinGraph } from '@urbit/api';
import React, { useEffect, useMemo, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useQuery } from '~/logic/lib/useQuery';

View File

@ -5,9 +5,7 @@ import {
Text
} from '@tlon/indigo-react';
import _ from 'lodash';
import { changePolicy, deSig, Enc } from '@urbit/api';
import { Group, GroupPolicy } from '@urbit/api/groups';
import { Association, metadataEdit, MetadataEditField } from '@urbit/api/metadata';
import { Association, changePolicy, deSig, Enc, Group, GroupPolicy, metadataEdit, MetadataEditField } from '@urbit/api';
import { Form, Formik, FormikHelpers } from 'formik';
import React from 'react';
import * as Yup from 'yup';

View File

@ -1,7 +1,5 @@
import { Box, Button, Col, Text } from '@tlon/indigo-react';
import { deSig } from '@urbit/api';
import { Group } from '@urbit/api/groups';
import { Association } from '@urbit/api/metadata';
import { Association, deSig, Group } from '@urbit/api';
import React, { useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import { resourceFromPath, roleForShip } from '~/logic/lib/group';

View File

@ -4,8 +4,7 @@ import {
Text
} from '@tlon/indigo-react';
import { ignoreGroup, listenGroup } from '@urbit/api';
import { Association } from '@urbit/api/metadata';
import { Association, ignoreGroup, listenGroup } from '@urbit/api';
import React from 'react';
import useHarkState from '~/logic/state/hark';
import { StatelessAsyncToggle } from '~/views/components/StatelessAsyncToggle';

View File

@ -1,5 +1,5 @@
import { Button, Icon, Row, Text } from '@tlon/indigo-react';
import { disableGroupFeed } from '@urbit/api/graph';
import { disableGroupFeed } from '@urbit/api';
import React, { useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
import { resourceFromPath } from '~/logic/lib/group';

View File

@ -1,12 +1,9 @@
import { Box, Col } from '@tlon/indigo-react';
import { Association, FlatGraph, FlatGraphNode, Group } from '@urbit/api';
import { arrToString, Association, FlatGraph, FlatGraphNode, Group } from '@urbit/api';
import bigInt from 'big-integer';
import React from 'react';
import { RouteComponentProps, useHistory } from 'react-router';
import { resourceFromPath } from '~/logic/lib/group';
import {
arrToString
} from '@urbit/api/lib/BigIntArrayOrderedMap';
import { keyEq, ThreadScroller } from '~/views/components/ThreadScroller';
import PostItem from './PostItem/PostItem';
import PostInput from './PostInput';

View File

@ -1,5 +1,5 @@
import { Action, Col, Icon, Row } from '@tlon/indigo-react';
import { Association, Post } from '@urbit/api';
import { Association, Post, removePosts } from '@urbit/api';
import React, { ReactElement } from 'react';
import { getPermalinkForGraph } from '~/logic/lib/permalinks';
import { useCopy } from '~/logic/lib/useCopy';
@ -8,7 +8,6 @@ import { resourceFromPath } from '~/logic/lib/group';
import Author from '~/views/components/Author';
import { Dropdown } from '~/views/components/Dropdown';
import airlock from '~/logic/api';
import { removePosts } from '@urbit/api/graph';
interface PostHeaderProps {
post: Post;
association: Association;

View File

@ -6,11 +6,10 @@ import React, {
} from 'react';
import { resourceFromPath } from '~/logic/lib/group';
import { Loading } from '~/views/components/Loading';
import { arrToString } from '@urbit/api/lib/BigIntArrayOrderedMap';
import useGraphState from '~/logic/state/graph';
import PostFlatFeed from './PostFlatFeed';
import PostInput from './PostInput';
import { Association, deSig, PermVariation } from '@urbit/api';
import { arrToString, Association, deSig, PermVariation } from '@urbit/api';
import { useParams, Switch, Route } from 'react-router';
import { useGroupForAssoc } from '~/logic/state/group';

View File

@ -5,8 +5,7 @@ import {
Row, Text
} from '@tlon/indigo-react';
import { invite } from '@urbit/api/groups';
import { Association } from '@urbit/api/metadata';
import { Association, invite } from '@urbit/api';
import { Form, Formik } from 'formik';
import _ from 'lodash';
import React, { useCallback, useRef } from 'react';

View File

@ -1,5 +1,5 @@
import { Box, Col, Text } from '@tlon/indigo-react';
import { invite } from '@urbit/api/groups';
import { invite } from '@urbit/api';
import { Form, Formik } from 'formik';
import _ from 'lodash';
import React from 'react';

View File

@ -6,10 +6,7 @@ import {
StatelessTextInput as Input, Text
} from '@tlon/indigo-react';
import { Contact, Contacts } from '@urbit/api/contacts';
import { addTag, removeMembers, changePolicy, Group, removeTag, RoleTags } from '@urbit/api/groups';
import { Association } from '@urbit/api/metadata';
import { deSig } from '@urbit/api';
import { addTag, Association, Contact, Contacts, changePolicy, deSig, Group, removeMembers, removeTag, RoleTags } from '@urbit/api';
import _ from 'lodash';
import f from 'lodash/fp';
import React, {

View File

@ -1,7 +1,5 @@
import { Box, Col, Text } from '@tlon/indigo-react';
import { Group } from '@urbit/api/groups';
import { deSig } from '@urbit/api';
import { Association } from '@urbit/api/metadata';
import { Association, deSig, Group } from '@urbit/api';
import React, { ReactElement, useCallback, useRef } from 'react';
import { Link, Route, RouteComponentProps, Switch } from 'react-router-dom';
import { resourceFromPath } from '~/logic/lib/group';

View File

@ -1,5 +1,4 @@
import { Association } from '@urbit/api/metadata';
import { AppName } from '@urbit/api';
import { AppName, Association } from '@urbit/api';
import React, { ReactElement } from 'react';
import Helmet from 'react-helmet';
import { Route, Switch } from 'react-router-dom';

View File

@ -1,7 +1,6 @@
import _ from 'lodash';
import { Box, Col, Icon, Text } from '@tlon/indigo-react';
import { Association } from '@urbit/api/metadata';
import { AppName } from '@urbit/api';
import { AppName, Association } from '@urbit/api';
import React, { ReactElement, ReactNode, useCallback, useState } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';

12
pkg/npm/api/.babelrc Normal file
View File

@ -0,0 +1,12 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": "> 1%",
"useBuiltIns": "usage",
"corejs": "3.19.1"
}
]
]
}

1
pkg/npm/api/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
tmp

View File

@ -1,5 +1,5 @@
declare module "urbit-ob" {
declare module 'urbit-ob' {
/**
* Convert a @p-encoded string to a decimal-encoded string.

View File

@ -1,6 +1,6 @@
import { Patp } from '../lib';
import BigIntOrderedMap from '../lib/BigIntOrderedMap';
import BigIntArrayOrderedMap from '../lib/BigIntArrayOrderedMap';
import { BigIntOrderedMap } from '../lib/BigIntOrderedMap';
import { BigIntArrayOrderedMap } from '../lib/BigIntArrayOrderedMap';
export interface TextContent {
text: string;

View File

@ -1,5 +1,3 @@
import _ from 'lodash';
import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types';
import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types';
import { GroupUpdate } from './update';
@ -97,6 +95,10 @@ export const changePolicy = (
}
});
export const makeResource = (ship: string, name: string) => {
return { ship, name };
};
export const join = (
ship: string,
name: string
@ -174,30 +176,32 @@ export const roleForShip = (
const roleShips = group?.tags?.role?.[role];
return roleShips && roleShips.has(ship) ? role : currRole;
}, undefined as RoleTags | undefined);
}
};
export const resourceFromPath = (path: Path): Resource => {
const [, , ship, name] = path.split('/');
return { ship, name };
}
export const makeResource = (ship: string, name: string) => {
return { ship, name };
}
};
export const isWriter = (group: Group, resource: string, ship: string) => {
const writers: Set<string> | undefined = _.get(
group,
['tags', 'graph', resource, 'writers'],
undefined
);
const graph = group.tags?.graph;
const writers: Set<string> | undefined = graph && (graph[resource] as any)?.writers;
const admins = group?.tags?.role?.admin ?? new Set();
if (_.isUndefined(writers)) {
if (typeof writers === 'undefined') {
return true;
} else {
return writers.has(ship) || admins.has(ship);
}
}
};
export const isHost = (
resource: string,
ship: string
): boolean => {
const [, , host] = resource.split('/');
return ship === host;
};
export const isChannelAdmin = (
group: Group,
@ -211,13 +215,4 @@ export const isChannelAdmin = (
role === 'admin' ||
role === 'moderator'
);
}
export const isHost = (
resource: string,
ship: string
): boolean => {
const [, , host] = resource.split('/');
return ship === host;
}
};

View File

@ -1,4 +1,4 @@
import { PatpNoSig, Path, Jug, ShipRank, Enc } from '../lib';
import { PatpNoSig, Path, ShipRank, Enc } from '../lib';
import { roleTags } from './index';
export type RoleTags = typeof roleTags[number];
@ -173,5 +173,3 @@ export type GroupUpdate =
| GroupUpdateInitialGroup;
export type GroupAction = Omit<GroupUpdate, 'initialGroup' | 'initial'>;

View File

@ -1,6 +1,5 @@
import { Poke, Scry } from '../lib';
import { Vats, Vat } from './types';
import _ from 'lodash';
export const getVats: Scry = {
app: 'hood',
@ -98,13 +97,17 @@ export function getBlockers(vats: Vats): string[] {
if(!blockedOn) {
return blockers;
}
_.forEach(_.omit(vats, 'base'), (vat, desk) => {
// assuming only %zuse
const kelvins = _.map((vat.arak.rail?.next || []), n => n.weft.kelvin);
if(!(kelvins.includes(blockedOn))) {
blockers.push(desk);
}
});
Object.entries(vats)
.filter(([desk]) => desk !== 'base')
.forEach(([desk, vat]) => {
// assuming only %zuse
const woofs = vat.arak.rail?.next || [];
const kelvins = woofs.map(n => n.weft.kelvin);
if(!(kelvins.includes(blockedOn))) {
blockers.push(desk);
}
});
return blockers;
}

View File

@ -7,7 +7,8 @@ export * as groups from './groups';
export * from './hark';
export * as hark from './hark';
export * from './invite';
export * as invite from './invite';
// this conflicts with /groups/lib invite
// export * as invite from './invite';
export * from './metadata';
export * as metadata from './metadata';
export * from './settings';
@ -16,6 +17,7 @@ export * from './s3';
export * as s3 from './s3';
export * from './lib';
export * from './lib/BigIntOrderedMap';
export * from './lib/BigIntArrayOrderedMap';
export * as hood from './hood';
export * from './hood';
export * as docket from './docket';

View File

@ -51,7 +51,7 @@ export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) {
return bLen - aLen;
}
export default class BigIntArrayOrderedMap<V> implements Iterable<[BigInteger[], V]> {
export class BigIntArrayOrderedMap<V> implements Iterable<[BigInteger[], V]> {
root: Record<string, V> = {}
cachedIter: [BigInteger[], V][] | null = null;
[immerable] = true;

View File

@ -14,7 +14,7 @@ function sortBigInt(a: BigInteger, b: BigInteger) {
return -1;
}
}
export default class BigIntOrderedMap<V> implements Iterable<[BigInteger, V]> {
export class BigIntOrderedMap<V> implements Iterable<[BigInteger, V]> {
root: Record<string, V> = {}
cachedIter: [BigInteger, V][] | null = null;
[immerable] = true;

View File

@ -1,5 +1,3 @@
import _ from "lodash";
import f from "lodash/fp";
import bigInt, { BigInteger } from "big-integer";
import { Resource } from "../groups/types";
@ -9,6 +7,36 @@ const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud
const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1
function chunk<T>(arr: T[], size: number): T[][] {
let chunk: T[] = [];
let newArray = [chunk];
for (let i = 0;i < arr.length;i++) {
if (chunk.length < size) {
chunk.push(arr[i])
} else {
chunk = [arr[i]]
newArray.push(chunk)
}
}
return newArray;
}
function dropWhile<T>(arr: T[], pred: (x: T) => boolean): T[] {
const newArray = arr.slice();
for (const item of arr) {
if (pred(item)) {
newArray.shift();
} else {
return newArray;
}
}
return newArray;
}
/**
* Given a bigint representing an urbit date, returns a unix timestamp.
*
@ -48,17 +76,11 @@ export function udToDec(ud: string): string {
}
export function decToUd(str: string): string {
return _.trimStart(
f.flow(
f.split(""),
f.reverse,
f.chunk(3),
f.map(f.flow(f.reverse, f.join(""))),
f.reverse,
f.join(".")
)(str),
"0."
);
const transform = chunk(str.split('').reverse(), 3)
.map(group => group.reverse().join(''))
.reverse()
.join('.')
return transform.replace(/^[0\.]+/g, '');
}
export function resourceAsPath(resource: Resource): string {
@ -161,11 +183,10 @@ export function uxToHex(ux: string) {
}
export const hexToUx = (hex: string): string => {
const ux = f.flow(
f.chunk(4),
f.map(x => _.dropWhile(x, (y: unknown) => y === 0).join('')),
f.join('.')
)(hex.split(''));
const ux = chunk(hex.split(''), 4).map(x => {
return dropWhile(x, y => y === '0').join('');
}).join('.');
return `0x${ux}`;
};
@ -207,21 +228,6 @@ export function stringToTa(str: string): string {
return "~." + out;
}
/**
* Formats a numbers as a `@ud` inserting dot where needed
*/
export function numToUd(num: number): string {
return f.flow(
f.split(''),
f.reverse,
f.chunk(3),
f.reverse,
f.map(s => s.join('')),
f.join('.')
)(num.toString())
}
export const buntPost = (): Post => ({
author: '',
contents: [],

View File

@ -2,7 +2,7 @@
* Martian embassy
*/
import BigIntOrderedMap from "./BigIntOrderedMap";
import { BigIntOrderedMap } from "./BigIntOrderedMap";
// an urbit style path rendered as string
export type Path = string;

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +1,52 @@
{
"name": "@urbit/api",
"version": "2.0.0",
"description": "",
"version": "2.1.0",
"description": "A library that provides bindings and types for Urbit's various userspace desks",
"repository": {
"type": "git",
"url": "ssh://git@github.com/urbit/urbit.git",
"directory": "pkg/npm/api"
},
"main": "dist/index.js",
"types": "dist/index.d",
"type": "module",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"jsdelivr": "dist/urbit-api.min.js",
"unpkg": "dist/urbit-api.min.js",
"types": "dist/index.d.ts",
"files": [
"dist/**"
],
"scripts": {
"test": "echo \"No test specified\" && exit 0",
"watch": "tsc -p tsconfig.json --watch",
"build": "tsc -p tsconfig.json",
"clean": "rm -rf dist/*",
"prepare": "npm run build"
"build": "npm run clean && rollup -c && npx tsc -p tsconfig.json",
"prepare": "npm run build",
"watch": "rollup -c -w",
"clean": "rm -rf dist/* types/*"
},
"author": "",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/lodash": "^4.14.168",
"@urbit/eslint-config": "^1.0.3",
"@babel/runtime": "^7.16.0",
"big-integer": "^1.6.48",
"core-js": "^3.19.1",
"immer": "^9.0.1",
"lodash": "^4.17.20",
"urbit-ob": "^5.0.1"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.0.6",
"@types/node": "^15.12.5",
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"@urbit/eslint-config": "^1.0.3",
"babel-eslint": "^10.1.0",
"eslint-plugin-react": "^7.24.0",
"onchange": "^7.1.0",
"rollup": "^2.59.0",
"rollup-plugin-analyzer": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"typescript": "^4.3.2"
}
}

View File

@ -0,0 +1,76 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonJS from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import babel from '@rollup/plugin-babel';
import typescript from 'rollup-plugin-typescript2';
import analyze from 'rollup-plugin-analyzer'
const input = ['./index.ts'];
// Skip certain warnings
function onwarn(warning) {
if (warning.code === 'THIS_IS_UNDEFINED') {
return;
}
console.warn(warning.message);
}
export default [
{
input,
onwarn,
plugins: [
nodeResolve({
extensions: ['.js', '.jsx', '.ts', '.tsx']
}),
commonJS(),
typescript(),
babel({
babelHelpers: 'bundled',
exclude: ['node_modules/**']
}),
terser({
ecma: 2017,
compress: true,
mangle: true
})
],
output: {
file: 'dist/urbit-api.min.js',
format: 'umd',
name: 'UrbitAPI', // this is the name of the global object
esModule: false,
exports: 'named',
sourcemap: true
}
},
{
input,
onwarn,
plugins: [
nodeResolve({
extensions: ['.js', '.jsx', '.ts', '.tsx']
}),
commonJS(),
typescript(),
analyze({
limit: 10
})
],
output: [
{
dir: 'dist/esm',
format: 'esm',
exports: 'named',
sourcemap: true
},
{
dir: 'dist/cjs',
format: 'cjs',
exports: 'named',
sourcemap: true
}
]
}
];

View File

@ -1,10 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"outDir": "./dist",
"module": "ES2020",
"outDir": "./tmp",
"module": "ESNext",
"noImplicitAny": true,
"target": "ES2017",
"target": "ESNext",
"pretty": true,
"moduleResolution": "node",
"esModuleInterop": true,
@ -14,6 +14,11 @@
"strict": false,
"noErrorTruncation": true
},
"exclude": ["node_modules", "./dist/**/*", "@types"],
"exclude": [
"node_modules",
"./dist/**/*",
"./tmp/**/*",
"rollup.config.ts"
],
"include": ["./*.ts"]
}

13
pkg/npm/http-api/.babelrc Normal file
View File

@ -0,0 +1,13 @@
{
"presets": [
"@babel/preset-typescript", //needed for .ts jest tests
[
"@babel/preset-env",
{
"targets": "> 1%",
"useBuiltIns": "usage",
"corejs": "3.19.1"
}
]
]
}

View File

@ -0,0 +1,4 @@
dist
node_modules
coverage
tmp

View File

@ -1,6 +0,0 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};

View File

@ -1,98 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demo</title>
<script src="browser.js"></script>
<script src="../dist/urbit-http-api.min.js"></script>
<style>
@import url("https://rsms.me/inter/inter.css");
@font-face {
font-family: "Source Code Pro";
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-regular.woff");
font-weight: 400;
}
body {
margin: 0 auto;
max-width: 70ch;
padding: 2ch;
font-family: 'Inter', sans-serif;
}
#mylog {
white-space: pre-wrap;
padding: 2ch;
background: black;
color: white;
font-family: 'Source Code Pro', monospace;
}
#mylog div {
margin-bottom: 1rem;
}
.chunk {
border-bottom: 1px dashed currentColor;
}
@import url('https://rsms.me/inter/inter.css');
@font-face {
font-family: 'Source Code Pro';
src: url('https://storage.googleapis.com/media.urbit.org/fonts/scp-regular.woff');
font-weight: 400;
}
body {
margin: 0 auto;
max-width: 70ch;
padding: 2ch;
font-family: 'Inter', sans-serif;
}
#mylog {
white-space: pre-wrap;
padding: 2ch;
background: black;
color: white;
font-family: 'Source Code Pro', monospace;
}
#mylog div {
margin-bottom: 1rem;
}
.chunk {
border-bottom: 1px dashed currentColor;
}
</style>
</head>
<body>
</head>
<body>
<details>
<summary>Show instructions</summary>
<p>Assuming you are running a fakezod on port 8080, run</p>
<code id="instructions">|cors-approve '{window.location.origin}'</code>
<p>in its dojo.</p>
<p>Press the button to run the code below. Output will be logged. You should see <code>&lt; ~zod: opening airlock</code> in your dojo.</code> Create a chat and send a message to see the events logged.</p>
<pre>window.airlock = await Urbit.authenticate({
<summary>Show instructions</summary>
<p>Assuming you are running a fakezod on port 8080, run</p>
<code id="instructions">|cors-approve '{window.location.origin}'</code>
<p>in its dojo.</p>
<p>
Press the button to run the code below. Output will be logged. You
should see <code>&lt; ~zod: opening airlock</code> in your dojo. Create
a chat and send a message to see the events logged.
</p>
<pre>
window.airlock = await UrbitHttpApi.Urbit.authenticate({
ship: 'zod',
url: 'localhost:8080',
code: 'lidlut-tabwed-pillex-ridrup',
verbose: true
});
window.airlock.subscribe('chat-view', '/primary', { event: console.log });</pre>
window.airlock.subscribe({
app: 'graph-store',
path: '/updates',
event: console.log
});</pre
>
</details>
<button id="blastoff" onclick="blastOff()">Blast Off</button>
<pre id="mylog">
</pre>
</body>
<script>
<pre id="mylog"></pre>
</body>
<script>
var baseLogFunction = console.log;
console.log = function(){
baseLogFunction.apply(console, arguments);
var chunk = document.createElement('div');
chunk.className = 'chunk';
console.log = function () {
baseLogFunction.apply(console, arguments);
var chunk = document.createElement('div');
chunk.className = 'chunk';
var args = Array.prototype.slice.call(arguments);
for(var i=0;i<args.length;i++){
const val = typeof args[i] === 'string' ? args[i] : JSON.stringify(args[i]);
var node = createLogNode(val);
chunk.appendChild(node);
}
document.querySelector("#mylog").insertBefore(chunk, document.querySelector("#mylog").firstChild);
var args = Array.prototype.slice.call(arguments);
for (var i = 0; i < args.length; i++) {
const val =
typeof args[i] === 'string' ? args[i] : JSON.stringify(args[i]);
var node = createLogNode(val);
chunk.appendChild(node);
}
document
.querySelector('#mylog')
.insertBefore(chunk, document.querySelector('#mylog').firstChild);
};
function createLogNode(message) {
var node = document.createElement('div');
node.className = 'message';
var textNode = document.createTextNode(message);
node.appendChild(textNode);
return node;
}
function createLogNode(message){
var node = document.createElement("div");
node.className = 'message';
var textNode = document.createTextNode(message);
node.appendChild(textNode);
return node;
}
window.onerror = function(message, url, linenumber) {
console.log("JavaScript error: " + message + " on line " +
linenumber + " for " + url);
}
window.onerror = function (message, url, linenumber) {
console.log(
'JavaScript error: ' +
message +
' on line ' +
linenumber +
' for ' +
url
);
};
const instructions = document.getElementById('instructions');
instructions.innerText = instructions.innerText.replace('{window.location.origin}', window.location.origin);
instructions.innerText = instructions.innerText.replace(
'{window.location.origin}',
window.location.origin
);
async function blastOff() {
window.airlock = await Urbit.authenticate({
ship: 'zod',
url: 'localhost:8080',
code: 'lidlut-tabwed-pillex-ridrup',
verbose: true
});
window.airlock.subscribe('chat-view', '/primary', { event: console.log });
document.body.removeChild(document.getElementById('blastoff'))
window.airlock = await UrbitHttpApi.Urbit.authenticate({
ship: 'zod',
url: 'localhost',
code: 'lidlut-tabwed-pillex-ridrup',
verbose: true,
});
window.airlock.subscribe({
app: 'graph-store',
path: '/updates',
event: console.log,
});
document.body.removeChild(document.getElementById('blastoff'));
}
</script>
</html>
</script>
</html>

View File

@ -23,7 +23,7 @@ module.exports = {
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
coverageDirectory: 'coverage',
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
@ -137,7 +137,7 @@ module.exports = {
// snapshotSerializers: [],
// The test environment that will be used for testing
testEnvironment: "jsdom",
testEnvironment: 'jsdom',
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
@ -166,7 +166,7 @@ module.exports = {
// testRunner: "jest-circus/runner",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
testURL: "http://localhost",
testURL: 'http://localhost',
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@urbit/http-api",
"version": "2.0.0",
"version": "2.1.0",
"license": "MIT",
"description": "Library to interact with an Urbit ship over HTTP",
"repository": {
@ -8,18 +8,21 @@
"url": "ssh://git@github.com/urbit/urbit.git",
"directory": "pkg/npm/http-api"
},
"main": "dist/index.js",
"type": "module",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"jsdelivr": "dist/urbit-http-api.min.js",
"unpkg": "dist/urbit-http-api.min.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"src"
"dist/**"
],
"scripts": {
"test": "jest",
"build": "tsc -p tsconfig.json",
"build": "npm run clean && rollup -c && npx tsc -p tsconfig.json",
"prepare": "npm run build",
"watch": "tsc -p tsconfig.json --watch",
"clean": "rm -rf dist/*"
"watch": "rollup -c -w",
"clean": "rm -rf dist/* types/*"
},
"prettier": {
"printWidth": 80,
@ -29,12 +32,12 @@
},
"author": "",
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
"@babel/preset-env": "^7.14.7",
"@babel/preset-typescript": "^7.12.1",
"@babel/core": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-typescript": "^7.16.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.0.6",
"@types/browser-or-node": "^1.2.0",
"@types/eventsource": "^1.1.5",
"@types/jest": "^26.0.24",
@ -42,29 +45,22 @@
"@typescript-eslint/eslint-plugin": "^4.7.0",
"@typescript-eslint/parser": "^4.7.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.2.1",
"clean-webpack-plugin": "^3.0.0",
"cross-fetch": "^3.1.4",
"event-target-polyfill": "0.0.3",
"fast-text-encoding": "^1.0.3",
"jest": "^27.0.6",
"onchange": "^7.1.0",
"tslib": "^2.0.3",
"rollup": "^2.59.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"typescript": "^3.9.7",
"util": "^0.12.3",
"web-streams-polyfill": "^3.0.3",
"webpack": "^5.4.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"yet-another-abortcontroller-polyfill": "0.0.4"
},
"dependencies": {
"@babel/runtime": "^7.12.5",
"@microsoft/fetch-event-source": "^2.0.0",
"browser-or-node": "^1.3.0",
"browserify-zlib": "^0.2.0",
"buffer": "^6.0.3",
"stream-browserify": "^3.0.0",
"stream-http": "^3.1.1"
"core-js": "^3.19.1"
}
}

View File

@ -0,0 +1,72 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonJS from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import babel from '@rollup/plugin-babel';
import typescript from 'rollup-plugin-typescript2';
const input = ['src/index.ts'];
// Skip certain warnings
function onwarn(warning) {
if (warning.code === 'THIS_IS_UNDEFINED') {
return;
}
console.warn(warning.message);
}
export default [
{
input,
onwarn,
plugins: [
nodeResolve({
extensions: ['.js', '.jsx', '.ts', '.tsx'],
}),
commonJS(),
typescript(),
babel({
babelHelpers: 'bundled',
exclude: ['node_modules/**'],
}),
terser({
ecma: 2017,
compress: true,
mangle: true,
}),
],
output: {
file: `dist/urbit-http-api.min.js`,
format: 'umd',
name: 'UrbitHttpApi', // this is the name of the global object
esModule: false,
exports: 'named',
sourcemap: true,
},
},
{
input,
onwarn,
plugins: [
nodeResolve({
extensions: ['.js', '.jsx', '.ts', '.tsx'],
}),
commonJS(),
typescript(),
],
output: [
{
dir: 'dist/esm',
format: 'esm',
exports: 'named',
sourcemap: true,
},
{
dir: 'dist/cjs',
format: 'cjs',
exports: 'named',
sourcemap: true,
},
],
},
];

View File

@ -1,8 +1,21 @@
import { isBrowser, isNode } from 'browser-or-node';
import { fetchEventSource, EventSourceMessage, EventStreamContentType } from '@microsoft/fetch-event-source';
import {
fetchEventSource,
EventSourceMessage,
} from '@microsoft/fetch-event-source';
import { Action, Scry, Thread, AuthenticationInterface, SubscriptionInterface, CustomEventHandler, PokeInterface, SubscriptionRequestInterface, headers, SSEOptions, PokeHandlers, Message, FatalError } from './types';
import { uncamelize, hexString } from './utils';
import {
Scry,
Thread,
AuthenticationInterface,
PokeInterface,
SubscriptionRequestInterface,
headers,
SSEOptions,
PokeHandlers,
Message,
} from './types';
import { hexString } from './utils';
/**
* A class for interacting with an urbit ship, given its URL and code
@ -32,7 +45,7 @@ export class Urbit {
/**
* A registry of requestId to successFunc/failureFunc
*
*
* These functions are registered during a +poke and are executed
* in the onServerEvent()/onServerError() callbacks. Only one of
* the functions will be called, and the outstanding poke will be
@ -43,16 +56,17 @@ export class Urbit {
/**
* A registry of requestId to subscription functions.
*
*
* These functions are registered during a +subscribe and are
* executed in the onServerEvent()/onServerError() callbacks. The
* event function will be called whenever a new piece of data on this
* subscription is available, which may be 0, 1, or many times. The
* disconnect function may be called exactly once.
*/
private outstandingSubscriptions: Map<number, SubscriptionRequestInterface> = new Map();
private outstandingSubscriptions: Map<number, SubscriptionRequestInterface> =
new Map();
/**
/**
* Our abort controller, used to close the connection
*/
private abort = new AbortController();
@ -94,7 +108,7 @@ export class Urbit {
credentials: 'include',
accept: '*',
headers,
signal: this.abort.signal
signal: this.abort.signal,
};
}
@ -102,15 +116,11 @@ export class Urbit {
* Constructs a new Urbit connection.
*
* @param url The URL (with protocol and port) of the ship to be accessed. If
* the airlock is running in a webpage served by the ship, this should just
* the airlock is running in a webpage served by the ship, this should just
* be the empty string.
* @param code The access code for the ship at that address
*/
constructor(
public url: string,
public code?: string,
public desk?: string
) {
constructor(public url: string, public code?: string, public desk?: string) {
if (isBrowser) {
window.addEventListener('beforeunload', this.delete);
}
@ -119,18 +129,27 @@ export class Urbit {
/**
* All-in-one hook-me-up.
*
*
* Given a ship, url, and code, this returns an airlock connection
* that is ready to go. It `|hi`s itself to create the channel,
* then opens the channel via EventSource.
*
*
*/
static async authenticate({ ship, url, code, verbose = false }: AuthenticationInterface) {
static async authenticate({
ship,
url,
code,
verbose = false,
}: AuthenticationInterface) {
const airlock = new Urbit(`http://${url}`, code);
airlock.verbose = verbose;
airlock.ship = ship;
await airlock.connect();
await airlock.poke({ app: 'hood', mark: 'helm-hi', json: 'opening airlock' });
await airlock.poke({
app: 'hood',
mark: 'helm-hi',
json: 'opening airlock',
});
await airlock.eventSource();
return airlock;
}
@ -141,13 +160,18 @@ export class Urbit {
*/
async connect(): Promise<void> {
if (this.verbose) {
console.log(`password=${this.code} `, isBrowser ? "Connecting in browser context at " + `${this.url}/~/login` : "Connecting from node context");
console.log(
`password=${this.code} `,
isBrowser
? 'Connecting in browser context at ' + `${this.url}/~/login`
: 'Connecting from node context'
);
}
return fetch(`${this.url}/~/login`, {
method: 'post',
body: `password=${this.code}`,
credentials: 'include',
}).then(response => {
}).then((response) => {
if (this.verbose) {
console.log('Received authentication response', response);
}
@ -160,25 +184,28 @@ export class Urbit {
}
});
}
/**
* Initializes the SSE pipe for the appropriate channel.
*/
async eventSource(): Promise<void> {
if(this.sseClientInitialized) {
if (this.sseClientInitialized) {
return Promise.resolve();
}
if(this.lastEventId === 0) {
if (this.lastEventId === 0) {
// Can't receive events until the channel is open,
// so poke and open then
await this.poke({ app: 'hood', mark: 'helm-hi', json: 'Opening API channel' });
await this.poke({
app: 'hood',
mark: 'helm-hi',
json: 'Opening API channel',
});
return;
}
this.sseClientInitialized = true;
return new Promise((resolve, reject) => {
const sseOptions: SSEOptions = {
headers: {}
headers: {},
};
if (isBrowser) {
sseOptions.withCredentials = true;
@ -200,7 +227,7 @@ export class Urbit {
} else {
const err = new Error('failed to open eventsource');
reject(err);
}
}
},
onmessage: (event: EventSourceMessage) => {
if (this.verbose) {
@ -208,14 +235,17 @@ export class Urbit {
}
if (!event.id) return;
this.lastEventId = parseInt(event.id, 10);
if((this.lastEventId - this.lastAcknowledgedEventId) > 20) {
if (this.lastEventId - this.lastAcknowledgedEventId > 20) {
this.ack(this.lastEventId);
}
if (event.data && JSON.parse(event.data)) {
const data: any = JSON.parse(event.data);
if (data.response === 'poke' && this.outstandingPokes.has(data.id)) {
if (
data.response === 'poke' &&
this.outstandingPokes.has(data.id)
) {
const funcs = this.outstandingPokes.get(data.id);
if (data.hasOwnProperty('ok')) {
funcs.onSuccess();
@ -226,22 +256,30 @@ export class Urbit {
console.error('Invalid poke response', data);
}
this.outstandingPokes.delete(data.id);
} else if (data.response === 'subscribe'
&& this.outstandingSubscriptions.has(data.id)) {
} else if (
data.response === 'subscribe' &&
this.outstandingSubscriptions.has(data.id)
) {
const funcs = this.outstandingSubscriptions.get(data.id);
if (data.hasOwnProperty('err')) {
console.error(data.err);
funcs.err(data.err, data.id);
this.outstandingSubscriptions.delete(data.id);
}
} else if (data.response === 'diff' && this.outstandingSubscriptions.has(data.id)) {
} else if (
data.response === 'diff' &&
this.outstandingSubscriptions.has(data.id)
) {
const funcs = this.outstandingSubscriptions.get(data.id);
try {
funcs.event(data.json);
} catch (e) {
console.error('Failed to call subscription event callback', e);
}
} else if (data.response === 'quit' && this.outstandingSubscriptions.has(data.id)) {
} else if (
data.response === 'quit' &&
this.outstandingSubscriptions.has(data.id)
) {
const funcs = this.outstandingSubscriptions.get(data.id);
funcs.quit(data);
this.outstandingSubscriptions.delete(data.id);
@ -253,7 +291,7 @@ export class Urbit {
},
onerror: (error) => {
console.warn(error);
if(!(error instanceof FatalError) && this.errorCount++ < 4) {
if (this.errorCount++ < 4) {
this.onRetry && this.onRetry();
return Math.pow(2, this.errorCount - 1) * 750;
}
@ -265,7 +303,7 @@ export class Urbit {
throw new Error('Ship unexpectedly closed the connection');
},
});
})
});
}
/**
@ -301,7 +339,7 @@ export class Urbit {
this.lastAcknowledgedEventId = eventId;
const message: Message = {
action: 'ack',
'event-id': eventId
'event-id': eventId,
};
await this.sendJSONtoChannel(message);
return eventId;
@ -311,12 +349,12 @@ export class Urbit {
const response = await fetch(this.channelUrl, {
...this.fetchOptions,
method: 'PUT',
body: JSON.stringify(json)
body: JSON.stringify(json),
});
if(!response.ok) {
if (!response.ok) {
throw new Error('Failed to PUT channel');
}
if(!this.sseClientInitialized) {
if (!this.sseClientInitialized) {
await this.eventSource();
}
}
@ -335,23 +373,23 @@ export class Urbit {
let done = false;
let id: number | null = null;
const quit = () => {
if(!done) {
if (!done) {
reject('quit');
}
};
const event = (e: T) => {
if(!done) {
if (!done) {
resolve(e);
this.unsubscribe(id);
}
}
};
const request = { app, path, event, err: reject, quit };
id = await this.subscribe(request);
if(timeout) {
if (timeout) {
setTimeout(() => {
if(!done) {
if (!done) {
done = true;
reject('timeout');
this.unsubscribe(id);
@ -369,18 +407,11 @@ export class Urbit {
* @param json The data to send
*/
async poke<T>(params: PokeInterface<T>): Promise<number> {
const {
app,
mark,
json,
ship,
onSuccess,
onError
} = {
onSuccess: () => { },
onError: () => { },
const { app, mark, json, ship, onSuccess, onError } = {
onSuccess: () => {},
onError: () => {},
ship: this.ship,
...params
...params,
};
const message: Message = {
id: this.getEventId(),
@ -388,7 +419,7 @@ export class Urbit {
ship,
app,
mark,
json
json,
};
const [send, result] = await Promise.all([
this.sendJSONtoChannel(message),
@ -401,9 +432,9 @@ export class Urbit {
onError: (event) => {
onError(event);
reject(event.err);
}
},
});
})
}),
]);
return result;
}
@ -417,19 +448,12 @@ export class Urbit {
* @param handlers Handlers to deal with various events of the subscription
*/
async subscribe(params: SubscriptionRequestInterface): Promise<number> {
const {
app,
path,
ship,
err,
event,
quit
} = {
err: () => { },
event: () => { },
quit: () => { },
const { app, path, ship, err, event, quit } = {
err: () => {},
event: () => {},
quit: () => {},
ship: this.ship,
...params
...params,
};
const message: Message = {
@ -437,15 +461,19 @@ export class Urbit {
action: 'subscribe',
ship,
app,
path
path,
};
this.outstandingSubscriptions.set(message.id, {
app, path, err, event, quit
app,
path,
err,
event,
quit,
});
await this.sendJSONtoChannel(message);
return message.id;
}
@ -458,7 +486,7 @@ export class Urbit {
return this.sendJSONtoChannel({
id: this.getEventId(),
action: 'unsubscribe',
subscription
subscription,
}).then(() => {
this.outstandingSubscriptions.delete(subscription);
});
@ -469,9 +497,14 @@ export class Urbit {
*/
delete() {
if (isBrowser) {
navigator.sendBeacon(this.channelUrl, JSON.stringify([{
action: 'delete'
}]));
navigator.sendBeacon(
this.channelUrl,
JSON.stringify([
{
action: 'delete',
},
])
);
} else {
// TODO
// this.sendMessage('delete');
@ -480,7 +513,7 @@ export class Urbit {
/**
* Scry into an gall agent at a path
*
*
* @typeParam T - Type of the scry result
*
* @remarks
@ -496,14 +529,17 @@ export class Urbit {
*/
async scry<T = any>(params: Scry): Promise<T> {
const { app, path } = params;
const response = await fetch(`${this.url}/~/scry/${app}${path}.json`, this.fetchOptions);
const response = await fetch(
`${this.url}/~/scry/${app}${path}.json`,
this.fetchOptions
);
return await response.json();
}
/**
* Run a thread
*
*
*
* @param inputMark The mark of the data being sent
* @param outputMark The mark of the data being returned
* @param threadName The thread to run
@ -511,15 +547,24 @@ export class Urbit {
* @returns The return value of the thread
*/
async thread<R, T = any>(params: Thread<T>): Promise<R> {
const { inputMark, outputMark, threadName, body, desk = this.desk } = params;
if(!desk) {
throw new Error("Must supply desk to run thread from");
const {
inputMark,
outputMark,
threadName,
body,
desk = this.desk,
} = params;
if (!desk) {
throw new Error('Must supply desk to run thread from');
}
const res = await fetch(`${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`, {
...this.fetchOptions,
method: 'POST',
body: JSON.stringify(body)
});
const res = await fetch(
`${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`,
{
...this.fetchOptions,
method: 'POST',
body: JSON.stringify(body),
}
);
return res.json();
}
@ -536,6 +581,4 @@ export class Urbit {
}
}
export default Urbit;

View File

@ -1,3 +0,0 @@
// import Urbit from '../../dist/browser';
// window.Urbit = Urbit;

View File

@ -1,14 +0,0 @@
// import Urbit from '../../dist/index';
// async function blastOff() {
// const airlock = await Urbit.authenticate({
// ship: 'zod',
// url: 'localhost:8080',
// code: 'lidlut-tabwed-pillex-ridrup',
// verbose: true
// });
// airlock.subscribe('chat-view', '/primary');
// }
// blastOff();

View File

@ -1,3 +1,3 @@
export * from './types';
import Urbit from './Urbit';
export { Urbit as default };
import { Urbit } from './Urbit';
export { Urbit as default, Urbit };

View File

@ -1,46 +1,17 @@
import * as http from 'http';
interface HttpResponse {
req: http.ClientRequest;
res: http.IncomingMessage;
data: string;
}
export function request(
url: string,
options: http.ClientRequestArgs,
body?: string
): Promise<HttpResponse> {
return new Promise<HttpResponse>((resolve, reject) => {
const req = http.request(url, options, res => {
let data = "";
res.on("data", chunk => {
data += chunk;
});
res.on("end", () => {
resolve({ req, res, data });
});
res.on("error", e => {
reject(e);
});
});
if (body) {
req.write(body);
}
req.end();
});
}
export function camelize(str: string) {
return str
.replace(/\s(.)/g, function($1: string) { return $1.toUpperCase(); })
.replace(/\s(.)/g, function ($1: string) {
return $1.toUpperCase();
})
.replace(/\s/g, '')
.replace(/^(.)/, function($1: string) { return $1.toLowerCase(); });
.replace(/^(.)/, function ($1: string) {
return $1.toLowerCase();
});
}
export function uncamelize(str: string, separator = '-') {
// Replace all capital letters by separator followed by lowercase one
var str = str.replace(/[A-Z]/g, function (letter: string) {
var str = str.replace(/[A-Z]/g, function (letter: string) {
return separator + letter.toLowerCase();
});
return str.replace(new RegExp('^' + separator), '');
@ -79,4 +50,4 @@ export function uid(): string {
str += _str + '.';
}
return str.slice(0, -1);
}
}

View File

@ -1,6 +1,4 @@
import Urbit from '../src';
import { Readable } from 'streams';
import 'jest';
function fakeSSE(messages = [], timeout = 0) {
@ -54,7 +52,7 @@ const fakeFetch = (body) => () =>
const wait = (ms: number) => new Promise((res) => setTimeout(res, ms));
process.on('unhandledRejection', () => {
process.on('unhandledRejection', (error) => {
console.error(error);
});
@ -91,7 +89,7 @@ describe('Initialisation', () => {
)
.mockImplementationOnce(() =>
Promise.resolve({ ok: true, body: fakeSSE([], 100) })
)
);
airlock.onError = jest.fn();
try {
@ -163,7 +161,7 @@ describe('subscription', () => {
)
.mockImplementationOnce(() =>
Promise.resolve({ ok: false, body: fakeSSE([ack(1, true)]) })
)
);
const params = {
app: 'app',

View File

@ -1,23 +1,24 @@
{
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "@types"],
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist", "tmp"],
"compilerOptions": {
"outDir": "./dist",
"outDir": "./tmp",
"module": "ESNext",
"noImplicitAny": true,
"target": "ESNext",
"pretty": true,
"lib": ["ESNext", "DOM"],
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"declaration": true,
"sourceMap": true,
"strict": false,
"pretty": true,
"noImplicitAny": true,
"noErrorTruncation": true,
"allowJs": true,
"baseUrl": ".",
"paths": {
"*" : ["./node_modules/@types/*", "*"]
"*": ["./node_modules/@types/*", "*"]
}
}
}