photon-msg 0.0.0-stage → 0.1.0

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +275 -2
  3. package/dist/args.d.ts +63 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +68 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +9 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/cli.d.ts +13 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +163 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/client.d.ts +37 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.js +68 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/commands/attachments.d.ts +25 -0
  20. package/dist/commands/attachments.d.ts.map +1 -0
  21. package/dist/commands/attachments.js +78 -0
  22. package/dist/commands/attachments.js.map +1 -0
  23. package/dist/commands/doctor.d.ts +9 -0
  24. package/dist/commands/doctor.d.ts.map +1 -0
  25. package/dist/commands/doctor.js +54 -0
  26. package/dist/commands/doctor.js.map +1 -0
  27. package/dist/commands/line.d.ts +51 -0
  28. package/dist/commands/line.d.ts.map +1 -0
  29. package/dist/commands/line.js +117 -0
  30. package/dist/commands/line.js.map +1 -0
  31. package/dist/commands/messages.d.ts +82 -0
  32. package/dist/commands/messages.d.ts.map +1 -0
  33. package/dist/commands/messages.js +163 -0
  34. package/dist/commands/messages.js.map +1 -0
  35. package/dist/commands/misc.d.ts +33 -0
  36. package/dist/commands/misc.d.ts.map +1 -0
  37. package/dist/commands/misc.js +61 -0
  38. package/dist/commands/misc.js.map +1 -0
  39. package/dist/commands/send.d.ts +107 -0
  40. package/dist/commands/send.d.ts.map +1 -0
  41. package/dist/commands/send.js +104 -0
  42. package/dist/commands/send.js.map +1 -0
  43. package/dist/commands/spaces.d.ts +56 -0
  44. package/dist/commands/spaces.d.ts.map +1 -0
  45. package/dist/commands/spaces.js +118 -0
  46. package/dist/commands/spaces.js.map +1 -0
  47. package/dist/commands/users.d.ts +34 -0
  48. package/dist/commands/users.d.ts.map +1 -0
  49. package/dist/commands/users.js +82 -0
  50. package/dist/commands/users.js.map +1 -0
  51. package/dist/config.d.ts +47 -0
  52. package/dist/config.d.ts.map +1 -0
  53. package/dist/config.js +77 -0
  54. package/dist/config.js.map +1 -0
  55. package/dist/content.d.ts +33 -0
  56. package/dist/content.d.ts.map +1 -0
  57. package/dist/content.js +287 -0
  58. package/dist/content.js.map +1 -0
  59. package/dist/errors.d.ts +62 -0
  60. package/dist/errors.d.ts.map +1 -0
  61. package/dist/errors.js +95 -0
  62. package/dist/errors.js.map +1 -0
  63. package/dist/help.d.ts +8 -0
  64. package/dist/help.d.ts.map +1 -0
  65. package/dist/help.js +177 -0
  66. package/dist/help.js.map +1 -0
  67. package/dist/index.d.ts +21 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +13 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/output.d.ts +35 -0
  72. package/dist/output.d.ts.map +1 -0
  73. package/dist/output.js +121 -0
  74. package/dist/output.js.map +1 -0
  75. package/dist/target.d.ts +34 -0
  76. package/dist/target.d.ts.map +1 -0
  77. package/dist/target.js +75 -0
  78. package/dist/target.js.map +1 -0
  79. package/dist/types.d.ts +200 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +8 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/upload.d.ts +33 -0
  84. package/dist/upload.d.ts.map +1 -0
  85. package/dist/upload.js +119 -0
  86. package/dist/upload.js.map +1 -0
  87. package/package.json +49 -4
package/dist/upload.js ADDED
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Attachment upload.
3
+ *
4
+ * The endpoint takes `multipart/related` with exactly two parts: a JSON
5
+ * descriptor followed by the raw bytes. We talk to it with fetch directly rather
6
+ * than through the SDK, because the SDK's upload method expects a
7
+ * pre-serialized body and would otherwise fight us over the content type.
8
+ */
9
+ import { readFile } from "node:fs/promises";
10
+ import { basename } from "node:path";
11
+ import { randomUUID } from "node:crypto";
12
+ import { CliError, EXIT, usageError } from "./errors.js";
13
+ const DEFAULT_BASE_URL = "https://api.photon.codes";
14
+ const TYPES = {
15
+ png: "image/png",
16
+ jpg: "image/jpeg",
17
+ jpeg: "image/jpeg",
18
+ gif: "image/gif",
19
+ webp: "image/webp",
20
+ heic: "image/heic",
21
+ pdf: "application/pdf",
22
+ mp3: "audio/mpeg",
23
+ m4a: "audio/mp4",
24
+ wav: "audio/wav",
25
+ ogg: "audio/ogg",
26
+ mp4: "video/mp4",
27
+ mov: "video/quicktime",
28
+ txt: "text/plain",
29
+ };
30
+ /** Best-effort content type from a filename extension. */
31
+ export function contentTypeFor(filename) {
32
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
33
+ return TYPES[ext] ?? "application/octet-stream";
34
+ }
35
+ /**
36
+ * Builds the `multipart/related` body by hand so the framing is exactly what the
37
+ * API documents: two parts, no extra headers. (The API rejects unsupported
38
+ * content-type parameters and part headers, which is why nothing else is added.)
39
+ */
40
+ export function buildMultipartRelated({ descriptor, bytes, contentType, boundary, }) {
41
+ const encoder = new TextEncoder();
42
+ const head = `--${boundary}\r\n` +
43
+ "Content-Type: application/json\r\n" +
44
+ "\r\n" +
45
+ `${JSON.stringify(descriptor)}\r\n` +
46
+ `--${boundary}\r\n` +
47
+ `Content-Type: ${contentType}\r\n` +
48
+ "\r\n";
49
+ const tail = `\r\n--${boundary}--\r\n`;
50
+ const headBytes = encoder.encode(head);
51
+ const tailBytes = encoder.encode(tail);
52
+ const body = new Uint8Array(headBytes.length + bytes.length + tailBytes.length);
53
+ body.set(headBytes, 0);
54
+ body.set(bytes, headBytes.length);
55
+ body.set(tailBytes, headBytes.length + bytes.length);
56
+ return body;
57
+ }
58
+ /** Loads bytes from a local path or an http(s) URL. */
59
+ async function loadSource(source, fetchImpl) {
60
+ if (/^https?:\/\//i.test(source)) {
61
+ const response = await fetchImpl(source);
62
+ if (!response.ok) {
63
+ throw new CliError(`Could not download ${source}: HTTP ${response.status}`);
64
+ }
65
+ const bytes = new Uint8Array(await response.arrayBuffer());
66
+ return { bytes, filename: basename(new URL(source).pathname) || "download" };
67
+ }
68
+ try {
69
+ const bytes = new Uint8Array(await readFile(source));
70
+ return { bytes, filename: basename(source) };
71
+ }
72
+ catch (error) {
73
+ throw usageError(`Could not read ${source}: ${error.message}`);
74
+ }
75
+ }
76
+ /** Creates an uploader bound to one project. Returns an attachment ID. */
77
+ export function createUploader({ apiKey, projectId, baseUrl = DEFAULT_BASE_URL, fetch: fetchImpl = globalThis.fetch, timeoutMs, }) {
78
+ return async function upload(source, { contentType } = {}) {
79
+ const { bytes, filename } = await loadSource(source, fetchImpl);
80
+ if (bytes.length === 0)
81
+ throw usageError(`${source} is empty.`);
82
+ const resolvedType = contentType ?? contentTypeFor(filename);
83
+ const boundary = `photonmsg${randomUUID().replaceAll("-", "")}`;
84
+ const descriptor = { contentType: resolvedType, sizeBytes: bytes.length, filename };
85
+ const body = buildMultipartRelated({ descriptor, bytes, contentType: resolvedType, boundary });
86
+ const url = new URL(`/v1/projects/${projectId}/attachments`, baseUrl).toString();
87
+ const response = await fetchImpl(url, {
88
+ method: "POST",
89
+ headers: {
90
+ Authorization: `Bearer ${apiKey}`,
91
+ "content-type": `multipart/related; boundary=${boundary}`,
92
+ "content-length": String(body.length),
93
+ "idempotency-key": `photon-msg:upload:${randomUUID()}`,
94
+ },
95
+ body,
96
+ ...(timeoutMs ? { signal: AbortSignal.timeout(timeoutMs) } : {}),
97
+ });
98
+ const text = await response.text();
99
+ let payload;
100
+ try {
101
+ payload = text ? JSON.parse(text) : {};
102
+ }
103
+ catch {
104
+ payload = { raw: text };
105
+ }
106
+ if (!response.ok) {
107
+ const detail = payload.detail ?? payload.title ?? text.slice(0, 200);
108
+ throw new CliError(`Attachment upload failed (HTTP ${response.status}): ${detail}`, {
109
+ exitCode: response.status === 401 ? EXIT.AUTH : response.status === 403 ? EXIT.FORBIDDEN : EXIT.FAILURE,
110
+ ...(payload.code ? { code: payload.code } : {}),
111
+ });
112
+ }
113
+ const id = payload.id ?? payload.attachmentId ?? payload.attachment?.id;
114
+ if (!id)
115
+ throw new CliError("Upload succeeded but the response carried no attachment ID.");
116
+ return id;
117
+ };
118
+ }
119
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "photon-msg",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Command-line client for sending and reading messages through the Photon API",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "photon-msg": "dist/bin.js",
9
+ "pmsg": "dist/bin.js"
10
+ },
11
+ "main": "dist/index.js",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.json",
28
+ "typecheck": "tsc -p tsconfig.json --noEmit",
29
+ "build:test": "tsc -p tsconfig.test.json",
30
+ "test": "npm run build:test && node --test \".test-build/test/*.test.js\"",
31
+ "test:watch": "npm run build:test && node --test --watch \".test-build/test/*.test.js\"",
32
+ "clean": "rm -rf dist .test-build",
33
+ "prepublishOnly": "npm run clean && npm run build",
34
+ "smoke": "npm run build && node dist/bin.js --help"
35
+ },
36
+ "keywords": [
37
+ "photon",
38
+ "imessage",
39
+ "sms",
40
+ "messaging",
41
+ "cli"
42
+ ],
43
+ "dependencies": {
44
+ "@photon-ai/api": "^0.6.0"
45
+ },
46
+ "types": "dist/index.d.ts",
47
+ "devDependencies": {
48
+ "@types/node": "^22.10.2",
49
+ "typescript": "^5.7.2"
50
+ }
51
+ }