naystack 1.1.13-beta.3 → 1.1.13

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.
@@ -0,0 +1,172 @@
1
+ // src/file/put.ts
2
+ import { waitUntil as waitUntil2 } from "@vercel/functions";
3
+ import { NextResponse as NextResponse3 } from "next/server";
4
+ import { v4 } from "uuid";
5
+
6
+ // src/auth/email/utils.ts
7
+ import { verify as verify2 } from "jsonwebtoken";
8
+
9
+ // src/auth/email/token.ts
10
+ import { compare } from "bcryptjs";
11
+ import { JsonWebTokenError, sign, verify } from "jsonwebtoken";
12
+ import { NextResponse } from "next/server";
13
+ function getUserIdFromRefreshToken(refreshKey, refreshToken) {
14
+ if (refreshToken)
15
+ try {
16
+ const decoded = verify(refreshToken, refreshKey);
17
+ if (typeof decoded !== "string" && typeof decoded.id === "number")
18
+ return decoded.id;
19
+ } catch (e) {
20
+ if (!(e instanceof JsonWebTokenError)) console.error(e, "errors");
21
+ return null;
22
+ }
23
+ return null;
24
+ }
25
+
26
+ // src/auth/utils/errors.ts
27
+ import { NextResponse as NextResponse2 } from "next/server";
28
+
29
+ // src/auth/email/utils.ts
30
+ var getUserContext = (refreshKey, signingKey, req) => {
31
+ const bearer = req.headers.get("authorization");
32
+ if (!bearer) {
33
+ const refresh = req.cookies.get("refresh")?.value;
34
+ const userId = getUserIdFromRefreshToken(refreshKey, refresh);
35
+ if (userId) return { refreshUserID: userId };
36
+ return null;
37
+ }
38
+ const token = bearer.slice(7);
39
+ try {
40
+ const res = verify2(token, signingKey);
41
+ if (typeof res === "string") {
42
+ return null;
43
+ }
44
+ return {
45
+ accessUserId: res.id
46
+ };
47
+ } catch {
48
+ }
49
+ return null;
50
+ };
51
+
52
+ // src/file/utils.ts
53
+ import { createHash } from "crypto";
54
+ import {
55
+ DeleteObjectCommand,
56
+ PutObjectCommand,
57
+ S3Client
58
+ } from "@aws-sdk/client-s3";
59
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
60
+ import { waitUntil } from "@vercel/functions";
61
+ var getS3Client = (options) => new S3Client({
62
+ region: options.region,
63
+ credentials: {
64
+ accessKeyId: options.awsKey,
65
+ secretAccessKey: options.awsSecret
66
+ }
67
+ });
68
+ var getURLPrefix = (options) => `https://${options.bucket}.s3.${options.region}.amazonaws.com/`;
69
+ function getHash(keys) {
70
+ return createHash("sha256").update(keys.join("/")).digest("hex");
71
+ }
72
+ var getUploadFileURL = (client, Bucket) => (keys, isPublic) => {
73
+ const command = new PutObjectCommand({
74
+ Bucket,
75
+ Key: getHash(keys),
76
+ ACL: isPublic ? "public-read" : void 0
77
+ });
78
+ return getSignedUrl(client, command, { expiresIn: 300 });
79
+ };
80
+ var getFileURL = (options) => (keys) => {
81
+ if (typeof keys === "string") return `${getURLPrefix(options)}${keys}`;
82
+ return `${getURLPrefix(options)}${getHash(keys)}`;
83
+ };
84
+ var uploadImage = (client, options) => async (url, key, blob) => {
85
+ const photoBlob = blob || await fetch(url).then((file) => file.blob());
86
+ if (photoBlob) {
87
+ waitUntil(uploadFile(client, options.bucket)(photoBlob, getHash(key)));
88
+ return getFileURL(options)(key);
89
+ }
90
+ return null;
91
+ };
92
+ var deleteImage = (client, options) => async (url) => {
93
+ const key = url.split(getURLPrefix(options))[1];
94
+ if (key) {
95
+ try {
96
+ await client.send(
97
+ new DeleteObjectCommand({
98
+ Bucket: options.bucket,
99
+ Key: key
100
+ })
101
+ );
102
+ return true;
103
+ } catch (e) {
104
+ console.error("ERROR", url, e);
105
+ }
106
+ }
107
+ return false;
108
+ };
109
+ var uploadFile = (client, Bucket) => async (file, key) => {
110
+ const fileBuffer = await file.arrayBuffer();
111
+ return client.send(
112
+ new PutObjectCommand({
113
+ Bucket,
114
+ Key: key,
115
+ ACL: "public-read",
116
+ Body: Buffer.from(fileBuffer),
117
+ ContentType: file.type,
118
+ ContentLength: file.size
119
+ })
120
+ );
121
+ };
122
+
123
+ // src/file/put.ts
124
+ var getFileUploadPutRoute = (options, client) => async (req) => {
125
+ const ctx = getUserContext(options.refreshKey, options.signingKey, req);
126
+ if (!ctx?.accessUserId)
127
+ return NextResponse3.json({ error: "unauthorized" }, { status: 401 });
128
+ const formData = await req.formData();
129
+ const type = formData.get("type");
130
+ const sync = Boolean(formData.get("sync"));
131
+ const file = formData.get("file");
132
+ const data = formData.get("data");
133
+ const imageKey = v4();
134
+ const url = file ? getFileURL(options)(imageKey) : null;
135
+ const handleKeyProcessing = async () => {
136
+ if (file) await uploadFile(client, options.bucket)(file, imageKey);
137
+ if (!type || !ctx.accessUserId) return;
138
+ const { deleteURL, response } = await options.processFile({
139
+ url,
140
+ type,
141
+ userId: ctx.accessUserId,
142
+ data: typeof data === "string" ? JSON.parse(data) : void 0
143
+ });
144
+ if (deleteURL) await deleteImage(client, options)(deleteURL);
145
+ return response;
146
+ };
147
+ if (!sync) {
148
+ waitUntil2(handleKeyProcessing());
149
+ return NextResponse3.json({ url });
150
+ } else {
151
+ return NextResponse3.json({
152
+ url,
153
+ response: await handleKeyProcessing()
154
+ });
155
+ }
156
+ };
157
+
158
+ // src/file/setup.ts
159
+ function setupFileUpload(options) {
160
+ const client = getS3Client(options);
161
+ return {
162
+ PUT: getFileUploadPutRoute(options, client),
163
+ getUploadFileURL: getUploadFileURL(client, options.bucket),
164
+ uploadImage: uploadImage(client, options),
165
+ deleteImage: deleteImage(client, options),
166
+ getFileURL: getFileURL(options),
167
+ uploadFile: uploadFile(client, options.bucket)
168
+ };
169
+ }
170
+ export {
171
+ setupFileUpload
172
+ };
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/file/utils.ts
21
+ var utils_exports = {};
22
+ __export(utils_exports, {
23
+ deleteImage: () => deleteImage,
24
+ getFileURL: () => getFileURL,
25
+ getS3Client: () => getS3Client,
26
+ getUploadFileURL: () => getUploadFileURL,
27
+ uploadFile: () => uploadFile,
28
+ uploadImage: () => uploadImage
29
+ });
30
+ module.exports = __toCommonJS(utils_exports);
31
+ var import_node_crypto = require("crypto");
32
+ var import_client_s3 = require("@aws-sdk/client-s3");
33
+ var import_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
34
+ var import_functions = require("@vercel/functions");
35
+ var getS3Client = (options) => new import_client_s3.S3Client({
36
+ region: options.region,
37
+ credentials: {
38
+ accessKeyId: options.awsKey,
39
+ secretAccessKey: options.awsSecret
40
+ }
41
+ });
42
+ var getURLPrefix = (options) => `https://${options.bucket}.s3.${options.region}.amazonaws.com/`;
43
+ function getHash(keys) {
44
+ return (0, import_node_crypto.createHash)("sha256").update(keys.join("/")).digest("hex");
45
+ }
46
+ var getUploadFileURL = (client, Bucket) => (keys, isPublic) => {
47
+ const command = new import_client_s3.PutObjectCommand({
48
+ Bucket,
49
+ Key: getHash(keys),
50
+ ACL: isPublic ? "public-read" : void 0
51
+ });
52
+ return (0, import_s3_request_presigner.getSignedUrl)(client, command, { expiresIn: 300 });
53
+ };
54
+ var getFileURL = (options) => (keys) => {
55
+ if (typeof keys === "string") return `${getURLPrefix(options)}${keys}`;
56
+ return `${getURLPrefix(options)}${getHash(keys)}`;
57
+ };
58
+ var uploadImage = (client, options) => async (url, key, blob) => {
59
+ const photoBlob = blob || await fetch(url).then((file) => file.blob());
60
+ if (photoBlob) {
61
+ (0, import_functions.waitUntil)(uploadFile(client, options.bucket)(photoBlob, getHash(key)));
62
+ return getFileURL(options)(key);
63
+ }
64
+ return null;
65
+ };
66
+ var deleteImage = (client, options) => async (url) => {
67
+ const key = url.split(getURLPrefix(options))[1];
68
+ if (key) {
69
+ try {
70
+ await client.send(
71
+ new import_client_s3.DeleteObjectCommand({
72
+ Bucket: options.bucket,
73
+ Key: key
74
+ })
75
+ );
76
+ return true;
77
+ } catch (e) {
78
+ console.error("ERROR", url, e);
79
+ }
80
+ }
81
+ return false;
82
+ };
83
+ var uploadFile = (client, Bucket) => async (file, key) => {
84
+ const fileBuffer = await file.arrayBuffer();
85
+ return client.send(
86
+ new import_client_s3.PutObjectCommand({
87
+ Bucket,
88
+ Key: key,
89
+ ACL: "public-read",
90
+ Body: Buffer.from(fileBuffer),
91
+ ContentType: file.type,
92
+ ContentLength: file.size
93
+ })
94
+ );
95
+ };
96
+ // Annotate the CommonJS export names for ESM import in node:
97
+ 0 && (module.exports = {
98
+ deleteImage,
99
+ getFileURL,
100
+ getS3Client,
101
+ getUploadFileURL,
102
+ uploadFile,
103
+ uploadImage
104
+ });
@@ -0,0 +1,13 @@
1
+ import * as _aws_sdk_client_s3 from '@aws-sdk/client-s3';
2
+ import { S3Client } from '@aws-sdk/client-s3';
3
+ import { SetupFileUploadOptions } from './setup.mjs';
4
+ import 'next/server';
5
+
6
+ declare const getS3Client: (options: SetupFileUploadOptions) => S3Client;
7
+ declare const getUploadFileURL: (client: S3Client, Bucket: string) => (keys: string[], isPublic?: boolean) => Promise<string>;
8
+ declare const getFileURL: (options: SetupFileUploadOptions) => (keys: string | string[]) => string;
9
+ declare const uploadImage: (client: S3Client, options: SetupFileUploadOptions) => (url: string, key: string[], blob?: Blob) => Promise<string | null>;
10
+ declare const deleteImage: (client: S3Client, options: SetupFileUploadOptions) => (url: string) => Promise<boolean>;
11
+ declare const uploadFile: (client: S3Client, Bucket: string) => (file: File | Blob, key: string) => Promise<_aws_sdk_client_s3.PutObjectCommandOutput>;
12
+
13
+ export { deleteImage, getFileURL, getS3Client, getUploadFileURL, uploadFile, uploadImage };
@@ -0,0 +1,13 @@
1
+ import * as _aws_sdk_client_s3 from '@aws-sdk/client-s3';
2
+ import { S3Client } from '@aws-sdk/client-s3';
3
+ import { SetupFileUploadOptions } from './setup.js';
4
+ import 'next/server';
5
+
6
+ declare const getS3Client: (options: SetupFileUploadOptions) => S3Client;
7
+ declare const getUploadFileURL: (client: S3Client, Bucket: string) => (keys: string[], isPublic?: boolean) => Promise<string>;
8
+ declare const getFileURL: (options: SetupFileUploadOptions) => (keys: string | string[]) => string;
9
+ declare const uploadImage: (client: S3Client, options: SetupFileUploadOptions) => (url: string, key: string[], blob?: Blob) => Promise<string | null>;
10
+ declare const deleteImage: (client: S3Client, options: SetupFileUploadOptions) => (url: string) => Promise<boolean>;
11
+ declare const uploadFile: (client: S3Client, Bucket: string) => (file: File | Blob, key: string) => Promise<_aws_sdk_client_s3.PutObjectCommandOutput>;
12
+
13
+ export { deleteImage, getFileURL, getS3Client, getUploadFileURL, uploadFile, uploadImage };
@@ -0,0 +1,78 @@
1
+ // src/file/utils.ts
2
+ import { createHash } from "crypto";
3
+ import {
4
+ DeleteObjectCommand,
5
+ PutObjectCommand,
6
+ S3Client
7
+ } from "@aws-sdk/client-s3";
8
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
9
+ import { waitUntil } from "@vercel/functions";
10
+ var getS3Client = (options) => new S3Client({
11
+ region: options.region,
12
+ credentials: {
13
+ accessKeyId: options.awsKey,
14
+ secretAccessKey: options.awsSecret
15
+ }
16
+ });
17
+ var getURLPrefix = (options) => `https://${options.bucket}.s3.${options.region}.amazonaws.com/`;
18
+ function getHash(keys) {
19
+ return createHash("sha256").update(keys.join("/")).digest("hex");
20
+ }
21
+ var getUploadFileURL = (client, Bucket) => (keys, isPublic) => {
22
+ const command = new PutObjectCommand({
23
+ Bucket,
24
+ Key: getHash(keys),
25
+ ACL: isPublic ? "public-read" : void 0
26
+ });
27
+ return getSignedUrl(client, command, { expiresIn: 300 });
28
+ };
29
+ var getFileURL = (options) => (keys) => {
30
+ if (typeof keys === "string") return `${getURLPrefix(options)}${keys}`;
31
+ return `${getURLPrefix(options)}${getHash(keys)}`;
32
+ };
33
+ var uploadImage = (client, options) => async (url, key, blob) => {
34
+ const photoBlob = blob || await fetch(url).then((file) => file.blob());
35
+ if (photoBlob) {
36
+ waitUntil(uploadFile(client, options.bucket)(photoBlob, getHash(key)));
37
+ return getFileURL(options)(key);
38
+ }
39
+ return null;
40
+ };
41
+ var deleteImage = (client, options) => async (url) => {
42
+ const key = url.split(getURLPrefix(options))[1];
43
+ if (key) {
44
+ try {
45
+ await client.send(
46
+ new DeleteObjectCommand({
47
+ Bucket: options.bucket,
48
+ Key: key
49
+ })
50
+ );
51
+ return true;
52
+ } catch (e) {
53
+ console.error("ERROR", url, e);
54
+ }
55
+ }
56
+ return false;
57
+ };
58
+ var uploadFile = (client, Bucket) => async (file, key) => {
59
+ const fileBuffer = await file.arrayBuffer();
60
+ return client.send(
61
+ new PutObjectCommand({
62
+ Bucket,
63
+ Key: key,
64
+ ACL: "public-read",
65
+ Body: Buffer.from(fileBuffer),
66
+ ContentType: file.type,
67
+ ContentLength: file.size
68
+ })
69
+ );
70
+ };
71
+ export {
72
+ deleteImage,
73
+ getFileURL,
74
+ getS3Client,
75
+ getUploadFileURL,
76
+ uploadFile,
77
+ uploadImage
78
+ };
@@ -8,10 +8,11 @@ type Values = object | string | number | boolean;
8
8
  type DeepPartial<T> = {
9
9
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
10
10
  };
11
+ type OtherTypes<T> = GraphQLScalarType<T, T> | [GraphQLScalarType<T, T>] | NumberConstructor | [NumberConstructor] | StringConstructor | [StringConstructor] | BooleanConstructor | [BooleanConstructor];
11
12
  interface BaseDefinition<T extends Values, U extends Values> {
12
- output: T extends object ? ClassType<DeepPartial<T>> | [ClassType<DeepPartial<T>>] : GraphQLScalarType<T, T> | NumberConstructor | StringConstructor | BooleanConstructor;
13
+ output: T extends object ? ClassType<DeepPartial<T>> | [ClassType<DeepPartial<T>>] : OtherTypes<T>;
13
14
  outputOptions?: ReturnOptions;
14
- input?: U extends object ? ClassType<U> | [ClassType<U>] : GraphQLScalarType<U, U> | NumberConstructor | StringConstructor | BooleanConstructor;
15
+ input?: U extends object ? ClassType<U> | [ClassType<U>] : OtherTypes<U>;
15
16
  inputOptions?: ArgsOptions;
16
17
  authorized?: boolean;
17
18
  }
@@ -8,10 +8,11 @@ type Values = object | string | number | boolean;
8
8
  type DeepPartial<T> = {
9
9
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
10
10
  };
11
+ type OtherTypes<T> = GraphQLScalarType<T, T> | [GraphQLScalarType<T, T>] | NumberConstructor | [NumberConstructor] | StringConstructor | [StringConstructor] | BooleanConstructor | [BooleanConstructor];
11
12
  interface BaseDefinition<T extends Values, U extends Values> {
12
- output: T extends object ? ClassType<DeepPartial<T>> | [ClassType<DeepPartial<T>>] : GraphQLScalarType<T, T> | NumberConstructor | StringConstructor | BooleanConstructor;
13
+ output: T extends object ? ClassType<DeepPartial<T>> | [ClassType<DeepPartial<T>>] : OtherTypes<T>;
13
14
  outputOptions?: ReturnOptions;
14
- input?: U extends object ? ClassType<U> | [ClassType<U>] : GraphQLScalarType<U, U> | NumberConstructor | StringConstructor | BooleanConstructor;
15
+ input?: U extends object ? ClassType<U> | [ClassType<U>] : OtherTypes<U>;
15
16
  inputOptions?: ArgsOptions;
16
17
  authorized?: boolean;
17
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naystack",
3
- "version": "1.1.13-beta.3",
3
+ "version": "1.1.13",
4
4
  "description": "A stack built with tight Next + Drizzle + GraphQL",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -32,6 +32,11 @@
32
32
  "types": "./dist/client/index.d.ts",
33
33
  "import": "./dist/client/index.esm.js",
34
34
  "require": "./dist/client/index.cjs.js"
35
+ },
36
+ "./file": {
37
+ "types": "./dist/file/index.d.ts",
38
+ "import": "./dist/file/index.esm.js",
39
+ "require": "./dist/file/index.cjs.js"
35
40
  }
36
41
  },
37
42
  "keywords": [
@@ -56,6 +61,8 @@
56
61
  "dependencies": {
57
62
  "@apollo/server": "^4.12.0",
58
63
  "@as-integrations/next": "^3.2.0",
64
+ "@aws-sdk/client-s3": "^3.913.0",
65
+ "@aws-sdk/s3-request-presigner": "^3.913.0",
59
66
  "@vercel/functions": "^3.1.0",
60
67
  "bcryptjs": "^3.0.2",
61
68
  "drizzle-orm": "^0.44.5",