Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

remix-typedjson

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

remix-typedjson - npm Package Compare versions

Comparing version 0.2.2 to 0.3.0

6

CHANGELOG.md
# CHANGELOG
## 🚀 v0.2.3
## 🚀 v0.3.0
- ✨ Add support for `typeddefer` and `<TypedAwait>` [#20](https://github.com/kiliman/remix-typedjson/issues/20)
## 🚀 v0.2.2
- 📦 Fix peer dependency to support Remix v2

@@ -6,0 +10,0 @@

4

dist/esm/index.d.ts

@@ -1,4 +0,4 @@

export { deserializeRemix, redirect, stringifyRemix, typedjson, useTypedActionData, useTypedFetcher, useTypedLoaderData, useTypedRouteLoaderData, } from './remix';
export type { RemixSerializedType, TypedFetcherWithComponents, TypedJsonResponse, TypedMetaFunction, UseDataFunctionReturn, } from './remix';
export { TypedAwait, deserializeRemix, redirect, stringifyRemix, typeddefer, typedjson, useTypedActionData, useTypedFetcher, useTypedLoaderData, useTypedRouteLoaderData, } from './remix';
export type { RemixSerializedType, TypedAwaitProps, TypedFetcherWithComponents, TypedJsonResponse, TypedMetaFunction, UseDataFunctionReturn, } from './remix';
export { applyMeta, deserialize, parse, registerCustomType, serialize, stringify, } from './typedjson';
export type { MetaType, TypedJsonResult } from './typedjson';

@@ -1,2 +0,2 @@

export { deserializeRemix, redirect, stringifyRemix, typedjson, useTypedActionData, useTypedFetcher, useTypedLoaderData, useTypedRouteLoaderData, } from './remix';
export { TypedAwait, deserializeRemix, redirect, stringifyRemix, typeddefer, typedjson, useTypedActionData, useTypedFetcher, useTypedLoaderData, useTypedRouteLoaderData, } from './remix';
export { applyMeta, deserialize, parse, registerCustomType, serialize, stringify, } from './typedjson';

@@ -0,1 +1,2 @@

/// <reference types="react" />
import { HtmlMetaDescriptor, Params, type FetcherWithComponents } from '@remix-run/react';

@@ -6,2 +7,3 @@ import type { MetaType } from './typedjson';

typedjson(): Promise<T>;
typeddefer(): Promise<T>;
};

@@ -21,2 +23,9 @@ export interface AppLoadContext {

export declare const typedjson: TypedJsonFunction;
export declare const typeddefer: TypedJsonFunction;
export type TypedAwaitProps<T> = {
resolve: Promise<T>;
errorElement?: React.ReactNode;
children: (data: T) => React.ReactNode;
};
export declare function TypedAwait<T>(props: TypedAwaitProps<T>): JSX.Element | null;
export declare function useTypedLoaderData<T = AppData>(): UseDataFunctionReturn<T>;

@@ -30,6 +39,6 @@ export declare function useTypedActionData<T = AppData>(): UseDataFunctionReturn<T> | null;

export type RemixSerializedType<T> = {
__obj__: T | null;
__meta__?: MetaType | null;
$$obj: T | null;
$$meta?: MetaType | null;
} & (T | {
__meta__?: MetaType;
$$meta?: MetaType;
});

@@ -36,0 +45,0 @@ export declare function stringifyRemix<T>(data: T): string | null | undefined;

@@ -1,2 +0,4 @@

import { useActionData, useFetcher, useLoaderData, useMatches, } from '@remix-run/react';
import { jsx as _jsx } from "react/jsx-runtime";
import { Await, useActionData, useFetcher, useLoaderData, useMatches, } from '@remix-run/react';
import { defer } from '@remix-run/server-runtime';
import * as _typedjson from './typedjson';

@@ -14,2 +16,38 @@ export const typedjson = (data, init = {}) => {

};
export const typeddefer = (data, init = {}) => {
// wrap any Promises in the data with new Promises that will serialize the
// resolved data and add the meta to the response
Object.entries(data).forEach(([key, value]) => {
if (value instanceof Promise) {
;
data[key] = value.then(resolvedData => {
const { meta } = _typedjson.serialize(resolvedData);
if (meta) {
;
resolvedData['$$meta'] = meta;
}
return resolvedData;
});
}
else {
const { meta } = _typedjson.serialize(data);
if (meta) {
;
data['$$meta'] = meta;
}
}
});
let responseInit = typeof init === 'number' ? { status: init } : init;
return defer(data, responseInit);
};
export function TypedAwait(props) {
if (!props.children)
return null;
return (_jsx(Await, { ...props, children: data => {
if (data === null)
return null;
let deserializedData = deserializeRemix(data);
return props.children(deserializedData);
} }));
}
export function useTypedLoaderData() {

@@ -42,6 +80,6 @@ const data = useLoaderData();

if (json.startsWith('{')) {
json = `${json.substring(0, json.length - 1)},\"__meta__\":${JSON.stringify(meta)}}`;
json = `${json.substring(0, json.length - 1)},\"$$meta\":${JSON.stringify(meta)}}`;
}
else if (json.startsWith('[')) {
json = `{"__obj__":${json},"__meta__":${JSON.stringify(meta)}}`;
json = `{"$$obj":${json},"$$meta":${JSON.stringify(meta)}}`;
}

@@ -54,13 +92,13 @@ }

return data;
if (data.__obj__) {
if (data.$$obj) {
// handle arrays wrapped in an object
return data.__meta__
? _typedjson.applyMeta(data.__obj__, data.__meta__)
: data.__obj__;
return data.$$meta
? _typedjson.applyMeta(data.$$obj, data.$$meta)
: data.$$obj;
}
else if (data.__meta__) {
// handle object with __meta__ key
else if (data.$$meta) {
// handle object with $$meta key
// remove before applying meta
const meta = data.__meta__;
delete data.__meta__;
const meta = data.$$meta;
delete data.$$meta;
return _typedjson.applyMeta(data, meta);

@@ -67,0 +105,0 @@ }

@@ -1,4 +0,4 @@

export { deserializeRemix, redirect, stringifyRemix, typedjson, useTypedActionData, useTypedFetcher, useTypedLoaderData, useTypedRouteLoaderData, } from './remix';
export type { RemixSerializedType, TypedFetcherWithComponents, TypedJsonResponse, TypedMetaFunction, UseDataFunctionReturn, } from './remix';
export { TypedAwait, deserializeRemix, redirect, stringifyRemix, typeddefer, typedjson, useTypedActionData, useTypedFetcher, useTypedLoaderData, useTypedRouteLoaderData, } from './remix';
export type { RemixSerializedType, TypedAwaitProps, TypedFetcherWithComponents, TypedJsonResponse, TypedMetaFunction, UseDataFunctionReturn, } from './remix';
export { applyMeta, deserialize, parse, registerCustomType, serialize, stringify, } from './typedjson';
export type { MetaType, TypedJsonResult } from './typedjson';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringify = exports.serialize = exports.registerCustomType = exports.parse = exports.deserialize = exports.applyMeta = exports.useTypedRouteLoaderData = exports.useTypedLoaderData = exports.useTypedFetcher = exports.useTypedActionData = exports.typedjson = exports.stringifyRemix = exports.redirect = exports.deserializeRemix = void 0;
exports.stringify = exports.serialize = exports.registerCustomType = exports.parse = exports.deserialize = exports.applyMeta = exports.useTypedRouteLoaderData = exports.useTypedLoaderData = exports.useTypedFetcher = exports.useTypedActionData = exports.typedjson = exports.typeddefer = exports.stringifyRemix = exports.redirect = exports.deserializeRemix = exports.TypedAwait = void 0;
var remix_1 = require("./remix");
Object.defineProperty(exports, "TypedAwait", { enumerable: true, get: function () { return remix_1.TypedAwait; } });
Object.defineProperty(exports, "deserializeRemix", { enumerable: true, get: function () { return remix_1.deserializeRemix; } });
Object.defineProperty(exports, "redirect", { enumerable: true, get: function () { return remix_1.redirect; } });
Object.defineProperty(exports, "stringifyRemix", { enumerable: true, get: function () { return remix_1.stringifyRemix; } });
Object.defineProperty(exports, "typeddefer", { enumerable: true, get: function () { return remix_1.typeddefer; } });
Object.defineProperty(exports, "typedjson", { enumerable: true, get: function () { return remix_1.typedjson; } });

@@ -9,0 +11,0 @@ Object.defineProperty(exports, "useTypedActionData", { enumerable: true, get: function () { return remix_1.useTypedActionData; } });

@@ -0,1 +1,2 @@

/// <reference types="react" />
import { HtmlMetaDescriptor, Params, type FetcherWithComponents } from '@remix-run/react';

@@ -6,2 +7,3 @@ import type { MetaType } from './typedjson';

typedjson(): Promise<T>;
typeddefer(): Promise<T>;
};

@@ -21,2 +23,9 @@ export interface AppLoadContext {

export declare const typedjson: TypedJsonFunction;
export declare const typeddefer: TypedJsonFunction;
export type TypedAwaitProps<T> = {
resolve: Promise<T>;
errorElement?: React.ReactNode;
children: (data: T) => React.ReactNode;
};
export declare function TypedAwait<T>(props: TypedAwaitProps<T>): JSX.Element | null;
export declare function useTypedLoaderData<T = AppData>(): UseDataFunctionReturn<T>;

@@ -30,6 +39,6 @@ export declare function useTypedActionData<T = AppData>(): UseDataFunctionReturn<T> | null;

export type RemixSerializedType<T> = {
__obj__: T | null;
__meta__?: MetaType | null;
$$obj: T | null;
$$meta?: MetaType | null;
} & (T | {
__meta__?: MetaType;
$$meta?: MetaType;
});

@@ -36,0 +45,0 @@ export declare function stringifyRemix<T>(data: T): string | null | undefined;

@@ -26,4 +26,6 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.redirect = exports.deserializeRemix = exports.stringifyRemix = exports.useTypedRouteLoaderData = exports.useTypedFetcher = exports.useTypedActionData = exports.useTypedLoaderData = exports.typedjson = void 0;
exports.redirect = exports.deserializeRemix = exports.stringifyRemix = exports.useTypedRouteLoaderData = exports.useTypedFetcher = exports.useTypedActionData = exports.useTypedLoaderData = exports.TypedAwait = exports.typeddefer = exports.typedjson = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("@remix-run/react");
const server_runtime_1 = require("@remix-run/server-runtime");
const _typedjson = __importStar(require("./typedjson"));

@@ -42,2 +44,40 @@ const typedjson = (data, init = {}) => {

exports.typedjson = typedjson;
const typeddefer = (data, init = {}) => {
// wrap any Promises in the data with new Promises that will serialize the
// resolved data and add the meta to the response
Object.entries(data).forEach(([key, value]) => {
if (value instanceof Promise) {
;
data[key] = value.then(resolvedData => {
const { meta } = _typedjson.serialize(resolvedData);
if (meta) {
;
resolvedData['$$meta'] = meta;
}
return resolvedData;
});
}
else {
const { meta } = _typedjson.serialize(data);
if (meta) {
;
data['$$meta'] = meta;
}
}
});
let responseInit = typeof init === 'number' ? { status: init } : init;
return (0, server_runtime_1.defer)(data, responseInit);
};
exports.typeddefer = typeddefer;
function TypedAwait(props) {
if (!props.children)
return null;
return ((0, jsx_runtime_1.jsx)(react_1.Await, { ...props, children: data => {
if (data === null)
return null;
let deserializedData = deserializeRemix(data);
return props.children(deserializedData);
} }));
}
exports.TypedAwait = TypedAwait;
function useTypedLoaderData() {

@@ -74,6 +114,6 @@ const data = (0, react_1.useLoaderData)();

if (json.startsWith('{')) {
json = `${json.substring(0, json.length - 1)},\"__meta__\":${JSON.stringify(meta)}}`;
json = `${json.substring(0, json.length - 1)},\"$$meta\":${JSON.stringify(meta)}}`;
}
else if (json.startsWith('[')) {
json = `{"__obj__":${json},"__meta__":${JSON.stringify(meta)}}`;
json = `{"$$obj":${json},"$$meta":${JSON.stringify(meta)}}`;
}

@@ -87,13 +127,13 @@ }

return data;
if (data.__obj__) {
if (data.$$obj) {
// handle arrays wrapped in an object
return data.__meta__
? _typedjson.applyMeta(data.__obj__, data.__meta__)
: data.__obj__;
return data.$$meta
? _typedjson.applyMeta(data.$$obj, data.$$meta)
: data.$$obj;
}
else if (data.__meta__) {
// handle object with __meta__ key
else if (data.$$meta) {
// handle object with $$meta key
// remove before applying meta
const meta = data.__meta__;
delete data.__meta__;
const meta = data.$$meta;
delete data.$$meta;
return _typedjson.applyMeta(data, meta);

@@ -100,0 +140,0 @@ }

{
"name": "remix-typedjson",
"version": "0.2.2",
"version": "0.3.0",
"description": "This package is a replacement for superjson to use in your Remix app. It handles a subset of types that `superjson` supports, but is faster and smaller.",

@@ -5,0 +5,0 @@ "browser": "/dist/esm/index.js",

@@ -54,4 +54,9 @@ # remix-typedjson

❌ export const loader: LoaderFunction = async ({request}) => {}
✅ export const loader = async ({request}: LoaderArgs) => {}
✅ export async function loader({request}: LoaderArgs) {}
❌ export const action: LoaderFunction = async ({request}) => {}
✅ export const loader = async ({request}: DataFunctionArgs) => {}
✅ export const action = async ({request}: DataFunctionArgs) => {}
✅ export async function loader({request}: DataFunctionArgs) {}
✅ export async function action({request}: DataFunctionArgs) {}
```

@@ -91,2 +96,53 @@

## typeddefer
✨ New in v0.3.0
Replacement for Remix `defer` helper. It also supports the optional `ResponseInit`, so you can return headers, etc.
### Usage
```js
return typeddefer({
fastData: { message: 'This is fast data', today: new Date() },
slowData: new Promise(resolve => setTimeout(resolve, 2000)).then(() => {
return { message: 'This is slow data', tomorrow: new Date() }
}),
})
```
In your route component, use the new `<TypedAwait>` component instead of the
Remix `<Await>` component
```js
export default function DeferRoute() {
const { fastData, slowData } = useTypedLoaderData<typeof loader>()
return (
<main>
<h1>Defer Route</h1>
<h2>Fast Data</h2>
<pre>{JSON.stringify(fastData, null, 2)}</pre>
<div>fastData.today is {fastData.today.toLocaleString()}</div>
<Suspense fallback={<p>Loading slow data...</p>}>
<TypedAwait
resolve={slowData}
errorElement={<p>Error loading slow data!</p>}
>
{slowData => (
<div>
<h2>Slow Data</h2>
<pre>{JSON.stringify(slowData, null, 2)}</pre>
<div>
slowData.tomorrow is {slowData.tomorrow.toLocaleString()}
</div>
</div>
)}
</TypedAwait>
</Suspense>
</main>
)
}
```
## `useTypedRouteLoaderData`

@@ -177,5 +233,3 @@

export function registerCustomType<T>(entry: CustomTypeEntry<T>) {
customTypeMap.set(entry.type, entry)
}
export function registerCustomType<T>(entry: CustomTypeEntry<T>)
```

@@ -182,0 +236,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc