@cedarjs/uploads 6.0.3-next.227

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 (113) hide show
  1. package/README.md +24 -0
  2. package/dist/authenticator.d.ts +38 -0
  3. package/dist/authenticator.d.ts.map +1 -0
  4. package/dist/authenticator.js +51 -0
  5. package/dist/cleanupStaleUploads.d.ts +50 -0
  6. package/dist/cleanupStaleUploads.d.ts.map +1 -0
  7. package/dist/cleanupStaleUploads.js +80 -0
  8. package/dist/constants.d.ts +7 -0
  9. package/dist/constants.d.ts.map +1 -0
  10. package/dist/constants.js +4 -0
  11. package/dist/deleteFile.d.ts +14 -0
  12. package/dist/deleteFile.d.ts.map +1 -0
  13. package/dist/deleteFile.js +18 -0
  14. package/dist/directives.d.ts +55 -0
  15. package/dist/directives.d.ts.map +1 -0
  16. package/dist/directives.js +174 -0
  17. package/dist/errors.d.ts +12 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +33 -0
  20. package/dist/fastify/plugin.d.ts +49 -0
  21. package/dist/fastify/plugin.d.ts.map +1 -0
  22. package/dist/fastify/plugin.js +241 -0
  23. package/dist/index.d.ts +34 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +88 -0
  26. package/dist/keys.d.ts +18 -0
  27. package/dist/keys.d.ts.map +1 -0
  28. package/dist/keys.js +25 -0
  29. package/dist/pending.d.ts +39 -0
  30. package/dist/pending.d.ts.map +1 -0
  31. package/dist/pending.js +94 -0
  32. package/dist/profiles.d.ts +49 -0
  33. package/dist/profiles.d.ts.map +1 -0
  34. package/dist/profiles.js +68 -0
  35. package/dist/providers/db.d.ts +9 -0
  36. package/dist/providers/db.d.ts.map +1 -0
  37. package/dist/providers/db.js +41 -0
  38. package/dist/providers/fs.d.ts +34 -0
  39. package/dist/providers/fs.d.ts.map +1 -0
  40. package/dist/providers/fs.js +125 -0
  41. package/dist/providers/s3.d.ts +25 -0
  42. package/dist/providers/s3.d.ts.map +1 -0
  43. package/dist/providers/s3.js +117 -0
  44. package/dist/s3.d.ts +3 -0
  45. package/dist/s3.d.ts.map +1 -0
  46. package/dist/s3.js +4 -0
  47. package/dist/serialize.d.ts +10 -0
  48. package/dist/serialize.d.ts.map +1 -0
  49. package/dist/serialize.js +22 -0
  50. package/dist/serveToken.d.ts +36 -0
  51. package/dist/serveToken.d.ts.map +1 -0
  52. package/dist/serveToken.js +45 -0
  53. package/dist/services.d.ts +70 -0
  54. package/dist/services.d.ts.map +1 -0
  55. package/dist/services.js +141 -0
  56. package/dist/storeFile.d.ts +27 -0
  57. package/dist/storeFile.d.ts.map +1 -0
  58. package/dist/storeFile.js +53 -0
  59. package/dist/targets.d.ts +14 -0
  60. package/dist/targets.d.ts.map +1 -0
  61. package/dist/targets.js +21 -0
  62. package/dist/types.d.ts +212 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +0 -0
  65. package/dist/uploadLoader.d.ts +11 -0
  66. package/dist/uploadLoader.d.ts.map +1 -0
  67. package/dist/uploadLoader.js +47 -0
  68. package/dist/uploadToken.d.ts +43 -0
  69. package/dist/uploadToken.d.ts.map +1 -0
  70. package/dist/uploadToken.js +61 -0
  71. package/dist/web/components/DbInput.d.ts +18 -0
  72. package/dist/web/components/DbInput.d.ts.map +1 -0
  73. package/dist/web/components/DbInput.js +46 -0
  74. package/dist/web/components/FsUploader.d.ts +6 -0
  75. package/dist/web/components/FsUploader.d.ts.map +1 -0
  76. package/dist/web/components/FsUploader.js +21 -0
  77. package/dist/web/components/S3Uploader.d.ts +6 -0
  78. package/dist/web/components/S3Uploader.d.ts.map +1 -0
  79. package/dist/web/components/S3Uploader.js +21 -0
  80. package/dist/web/components/UppyUploader.d.ts +23 -0
  81. package/dist/web/components/UppyUploader.d.ts.map +1 -0
  82. package/dist/web/components/UppyUploader.js +72 -0
  83. package/dist/web/createUppy.d.ts +62 -0
  84. package/dist/web/createUppy.d.ts.map +1 -0
  85. package/dist/web/createUppy.js +82 -0
  86. package/dist/web/graphql.d.ts +48 -0
  87. package/dist/web/graphql.d.ts.map +1 -0
  88. package/dist/web/graphql.js +36 -0
  89. package/dist/web/hooks/useDbUpload.d.ts +31 -0
  90. package/dist/web/hooks/useDbUpload.d.ts.map +1 -0
  91. package/dist/web/hooks/useDbUpload.js +80 -0
  92. package/dist/web/hooks/useFsUpload.d.ts +20 -0
  93. package/dist/web/hooks/useFsUpload.d.ts.map +1 -0
  94. package/dist/web/hooks/useFsUpload.js +58 -0
  95. package/dist/web/hooks/useS3Upload.d.ts +23 -0
  96. package/dist/web/hooks/useS3Upload.d.ts.map +1 -0
  97. package/dist/web/hooks/useS3Upload.js +99 -0
  98. package/dist/web/hooks/useUploadToken.d.ts +34 -0
  99. package/dist/web/hooks/useUploadToken.d.ts.map +1 -0
  100. package/dist/web/hooks/useUploadToken.js +60 -0
  101. package/dist/web/hooks/useUppyUpload.d.ts +23 -0
  102. package/dist/web/hooks/useUppyUpload.d.ts.map +1 -0
  103. package/dist/web/hooks/useUppyUpload.js +76 -0
  104. package/dist/web/index.d.ts +22 -0
  105. package/dist/web/index.d.ts.map +1 -0
  106. package/dist/web/index.js +36 -0
  107. package/dist/webhooks/s3.d.ts +52 -0
  108. package/dist/webhooks/s3.d.ts.map +1 -0
  109. package/dist/webhooks/s3.js +122 -0
  110. package/dist/webhooks/sns.d.ts +34 -0
  111. package/dist/webhooks/sns.d.ts.map +1 -0
  112. package/dist/webhooks/sns.js +131 -0
  113. package/package.json +147 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sns.d.ts","sourceRoot":"","sources":["../../src/webhooks/sns.ts"],"names":[],"mappings":"AAIA,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,GAAG,0BAA0B,GAAG,yBAAyB,CAAA;IAC7E,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAiCD,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,QAAS,CAAA;AAQ1C,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAmBhE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,QAY9C;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAY3D;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;AAkD/D,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,UAAU,EACnB,EACE,QAAQ,EACR,gBAA0C,GAC3C,EAAE,uBAAuB,GACzB,OAAO,CAAC,IAAI,CAAC,CA0Cf"}
@@ -0,0 +1,131 @@
1
+ import { createPublicKey, verify } from "node:crypto";
2
+ import { UploadError } from "../errors.js";
3
+ const SIGNED_FIELDS = {
4
+ Notification: [
5
+ "Message",
6
+ "MessageId",
7
+ "Subject",
8
+ "Timestamp",
9
+ "TopicArn",
10
+ "Type"
11
+ ],
12
+ SubscriptionConfirmation: [
13
+ "Message",
14
+ "MessageId",
15
+ "SubscribeURL",
16
+ "Timestamp",
17
+ "Token",
18
+ "TopicArn",
19
+ "Type"
20
+ ],
21
+ UnsubscribeConfirmation: [
22
+ "Message",
23
+ "MessageId",
24
+ "SubscribeURL",
25
+ "Timestamp",
26
+ "Token",
27
+ "TopicArn",
28
+ "Type"
29
+ ]
30
+ };
31
+ const SNS_HOST = /^sns\.[a-z0-9-]+\.amazonaws\.com(\.cn)?$/;
32
+ const SNS_FETCH_TIMEOUT_MS = 1e4;
33
+ const CERT_CACHE_LIMIT = 16;
34
+ const CERT_CACHE_TTL_MS = 60 * 60 * 1e3;
35
+ function isSnsMessage(value) {
36
+ if (typeof value !== "object" || value === null) {
37
+ return false;
38
+ }
39
+ const m = value;
40
+ return (m.Type === "Notification" || m.Type === "SubscriptionConfirmation" || m.Type === "UnsubscribeConfirmation") && typeof m.MessageId === "string" && typeof m.TopicArn === "string" && typeof m.Message === "string" && typeof m.Timestamp === "string" && typeof m.SignatureVersion === "string" && typeof m.Signature === "string" && typeof m.SigningCertURL === "string";
41
+ }
42
+ function assertTrustedSnsUrl(url) {
43
+ let parsed;
44
+ try {
45
+ parsed = new URL(url);
46
+ } catch {
47
+ throw new UploadError("FORBIDDEN", "Invalid SNS URL.");
48
+ }
49
+ if (parsed.protocol !== "https:" || !SNS_HOST.test(parsed.hostname)) {
50
+ throw new UploadError("FORBIDDEN", "Untrusted SNS URL.");
51
+ }
52
+ }
53
+ function snsStringToSign(message) {
54
+ const lines = [];
55
+ for (const field of SIGNED_FIELDS[message.Type]) {
56
+ const value = message[field];
57
+ if (typeof value === "string") {
58
+ lines.push(field, value);
59
+ }
60
+ }
61
+ return lines.join("\n") + "\n";
62
+ }
63
+ const certCache = /* @__PURE__ */ new Map();
64
+ async function defaultFetchCertificate(url) {
65
+ const now = Date.now();
66
+ const cached = certCache.get(url);
67
+ if (cached && cached.expiresAt > now) {
68
+ return cached.pending;
69
+ }
70
+ const pending = fetch(url, {
71
+ signal: AbortSignal.timeout(SNS_FETCH_TIMEOUT_MS)
72
+ }).then(async (res) => {
73
+ if (!res.ok) {
74
+ throw new UploadError(
75
+ "FORBIDDEN",
76
+ `Could not fetch the SNS signing certificate (HTTP ${res.status}).`
77
+ );
78
+ }
79
+ return res.text();
80
+ });
81
+ pending.catch(() => certCache.delete(url));
82
+ if (certCache.size >= CERT_CACHE_LIMIT) {
83
+ const oldest = certCache.keys().next().value;
84
+ if (oldest !== void 0) {
85
+ certCache.delete(oldest);
86
+ }
87
+ }
88
+ certCache.set(url, { pending, expiresAt: now + CERT_CACHE_TTL_MS });
89
+ return pending;
90
+ }
91
+ async function verifySnsMessage(message, {
92
+ topicArn,
93
+ fetchCertificate = defaultFetchCertificate
94
+ }) {
95
+ if (message.TopicArn !== topicArn) {
96
+ throw new UploadError(
97
+ "FORBIDDEN",
98
+ `SNS message is from topic '${message.TopicArn}', not the configured topic.`
99
+ );
100
+ }
101
+ assertTrustedSnsUrl(message.SigningCertURL);
102
+ const algorithm = message.SignatureVersion === "1" ? "RSA-SHA1" : message.SignatureVersion === "2" ? "RSA-SHA256" : null;
103
+ if (!algorithm) {
104
+ throw new UploadError(
105
+ "FORBIDDEN",
106
+ `Unsupported SNS signature version '${message.SignatureVersion}'.`
107
+ );
108
+ }
109
+ const certificate = await fetchCertificate(message.SigningCertURL);
110
+ let valid = false;
111
+ try {
112
+ valid = verify(
113
+ algorithm,
114
+ Buffer.from(snsStringToSign(message), "utf8"),
115
+ createPublicKey(certificate),
116
+ Buffer.from(message.Signature, "base64")
117
+ );
118
+ } catch (e) {
119
+ throw new UploadError("FORBIDDEN", "Could not verify SNS signature.", e);
120
+ }
121
+ if (!valid) {
122
+ throw new UploadError("FORBIDDEN", "Invalid SNS signature.");
123
+ }
124
+ }
125
+ export {
126
+ SNS_FETCH_TIMEOUT_MS,
127
+ assertTrustedSnsUrl,
128
+ isSnsMessage,
129
+ snsStringToSign,
130
+ verifySnsMessage
131
+ };
package/package.json ADDED
@@ -0,0 +1,147 @@
1
+ {
2
+ "name": "@cedarjs/uploads",
3
+ "version": "6.0.3-next.227",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/cedarjs/cedar.git",
7
+ "directory": "packages/uploads"
8
+ },
9
+ "license": "MIT",
10
+ "type": "module",
11
+ "exports": {
12
+ ".": {
13
+ "default": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "./s3": {
19
+ "default": {
20
+ "types": "./dist/s3.d.ts",
21
+ "default": "./dist/s3.js"
22
+ }
23
+ },
24
+ "./web": {
25
+ "default": {
26
+ "types": "./dist/web/index.d.ts",
27
+ "default": "./dist/web/index.js"
28
+ }
29
+ }
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "!dist/**/*.test.d.*"
34
+ ],
35
+ "scripts": {
36
+ "build": "node ./build.mts",
37
+ "build:pack": "yarn pack -o cedarjs-uploads.tgz",
38
+ "build:types": "tsc --build --verbose ./tsconfig.build.json",
39
+ "check:attw": "yarn cedar-fwtools-attw",
40
+ "check:package": "concurrently npm:check:attw yarn publint",
41
+ "setup:test": "npx prisma db push --accept-data-loss --config ./src/__tests__/prisma.config.ts && npx prisma generate --config ./src/__tests__/prisma.config.ts",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest watch"
44
+ },
45
+ "dependencies": {
46
+ "@cedarjs/api": "6.0.3-next.227",
47
+ "@cedarjs/context": "6.0.3-next.227",
48
+ "@cedarjs/graphql-server": "6.0.3-next.227",
49
+ "@fastify/multipart": "9.4.0",
50
+ "graphql": "16.14.2",
51
+ "mime-types": "2.1.35"
52
+ },
53
+ "devDependencies": {
54
+ "@apollo/client": "4.3.0",
55
+ "@arethetypeswrong/cli": "0.18.5",
56
+ "@aws-sdk/client-s3": "3.1131.0",
57
+ "@aws-sdk/s3-request-presigner": "3.1131.0",
58
+ "@cedarjs/framework-tools": "6.0.3-next.227",
59
+ "@cedarjs/web": "6.0.3-next.227",
60
+ "@prisma/adapter-better-sqlite3": "7.10.0",
61
+ "@prisma/client": "7.10.0",
62
+ "@testing-library/dom": "10.4.1",
63
+ "@testing-library/jest-dom": "6.9.1",
64
+ "@testing-library/react": "16.3.3",
65
+ "@types/aws-lambda": "8.10.163",
66
+ "@types/better-sqlite3": "7.6.13",
67
+ "@types/mime-types": "2.1.4",
68
+ "@types/react": "^19.2.0",
69
+ "@types/react-dom": "^19.2.0",
70
+ "@uppy/aws-s3": "6.1.0",
71
+ "@uppy/core": "6.0.1",
72
+ "@uppy/dashboard": "6.0.0",
73
+ "@uppy/drag-drop": "6.0.0",
74
+ "@uppy/react": "6.0.0",
75
+ "@uppy/xhr-upload": "6.0.0",
76
+ "better-sqlite3": "12.11.1",
77
+ "concurrently": "9.2.4",
78
+ "esbuild": "0.28.2",
79
+ "fastify": "5.12.4",
80
+ "jsdom": "27.4.0",
81
+ "prisma": "7.10.0",
82
+ "publint": "0.3.24",
83
+ "react": "19.3.0",
84
+ "react-dom": "19.3.0",
85
+ "typescript": "5.9.3",
86
+ "vitest": "4.1.11",
87
+ "zx": "8.8.5"
88
+ },
89
+ "peerDependencies": {
90
+ "@apollo/client": "4.3.0",
91
+ "@aws-sdk/client-s3": "^3.0.0",
92
+ "@aws-sdk/s3-request-presigner": "^3.0.0",
93
+ "@cedarjs/web": "6.0.3-next.227",
94
+ "@uppy/aws-s3": "^6.0.0",
95
+ "@uppy/core": "^6.0.0",
96
+ "@uppy/dashboard": "^6.0.0",
97
+ "@uppy/drag-drop": "^6.0.0",
98
+ "@uppy/react": "^6.0.0",
99
+ "@uppy/xhr-upload": "^6.0.0",
100
+ "fastify": "5.12.4",
101
+ "react": "19.3.0"
102
+ },
103
+ "peerDependenciesMeta": {
104
+ "@apollo/client": {
105
+ "optional": true
106
+ },
107
+ "@aws-sdk/client-s3": {
108
+ "optional": true
109
+ },
110
+ "@aws-sdk/s3-request-presigner": {
111
+ "optional": true
112
+ },
113
+ "@cedarjs/web": {
114
+ "optional": true
115
+ },
116
+ "@uppy/aws-s3": {
117
+ "optional": true
118
+ },
119
+ "@uppy/core": {
120
+ "optional": true
121
+ },
122
+ "@uppy/dashboard": {
123
+ "optional": true
124
+ },
125
+ "@uppy/drag-drop": {
126
+ "optional": true
127
+ },
128
+ "@uppy/react": {
129
+ "optional": true
130
+ },
131
+ "@uppy/xhr-upload": {
132
+ "optional": true
133
+ },
134
+ "fastify": {
135
+ "optional": true
136
+ },
137
+ "react": {
138
+ "optional": true
139
+ }
140
+ },
141
+ "engines": {
142
+ "node": ">=24"
143
+ },
144
+ "publishConfig": {
145
+ "access": "public"
146
+ }
147
+ }