@effect-app/vue 2.75.6 → 2.77.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.
@@ -16,7 +16,7 @@ import { I18n } from "./intl.js"
16
16
  import { WithToast } from "./withToast.js"
17
17
 
18
18
  type IntlRecord = Record<string, PrimitiveType | FormatXMLElementFn<string, string>>
19
- type FnOptions<I18nCustomKey extends string, State extends IntlRecord> = {
19
+ type FnOptions<I18nCustomKey extends string, State extends IntlRecord | undefined> = {
20
20
  i18nCustomKey?: I18nCustomKey
21
21
  /**
22
22
  * passed to the i18n formatMessage calls so you can use it in translation messagee
@@ -45,7 +45,8 @@ export const DefaultIntl = {
45
45
  "handle.request_error": "Die Anfrage konnte nicht gesendet werden:\n{error}",
46
46
  "handle.unexpected_error2": "{action} unerwarteter Fehler, probieren sie es in kurze nochmals.",
47
47
 
48
- "handle.unexpected_error": "Unerwarteter Fehler:\n{error}"
48
+ "handle.unexpected_error": "Unerwarteter Fehler:\n{error}",
49
+ "handle.not_found": "Das gesuchte war nicht gefunden"
49
50
  },
50
51
  en: {
51
52
  "handle.confirmation": "Confirm {action}?",
@@ -59,13 +60,21 @@ export const DefaultIntl = {
59
60
  "handle.response_error": "The request was not successful:\n{error}",
60
61
  "handle.unexpected_error2": "{action} unexpected error, please try again shortly.",
61
62
 
62
- "handle.unexpected_error": "Unexpected Error:\n{error}"
63
+ "handle.unexpected_error": "Unexpected Error:\n{error}",
64
+ "handle.not_found": "The requested item was not found."
63
65
  }
64
66
  }
65
67
 
66
68
  export class CommandContext extends Effect.Tag("CommandContext")<
67
69
  CommandContext,
68
- { id: string; i18nKey: string; action: string; namespace: string; namespaced: (key: string) => string }
70
+ {
71
+ id: string
72
+ i18nKey: string
73
+ action: string
74
+ namespace: string
75
+ namespaced: (key: string) => string
76
+ state?: IntlRecord | undefined
77
+ }
69
78
  >() {}
70
79
 
71
80
  export type EmitWithCallback<A, Event extends string> = (event: Event, value: A, onDone: () => void) => void
@@ -86,11 +95,11 @@ export declare namespace Commander {
86
95
  i18nKey: I18nKey
87
96
  namespace: `action.${I18nKey}`
88
97
  namespaced: <K extends string>(k: K) => `action.${I18nKey}.${K}`
89
- action: string
90
98
  }
91
99
  export interface CommandProps<A, E, Id extends string, I18nKey extends string>
92
100
  extends CommandContextLocal<Id, I18nKey>
93
101
  {
102
+ action: string
94
103
  result: Result<A, E>
95
104
  waiting: boolean
96
105
  }
@@ -937,7 +946,7 @@ const renderErrorMaker = I18n.use(
937
946
  (e: E, ...args: Args): string => {
938
947
  if (errorRenderer) {
939
948
  const m = errorRenderer(e, action, ...args)
940
- if (m) {
949
+ if (m !== undefined) {
941
950
  return m
942
951
  }
943
952
  }
@@ -955,6 +964,9 @@ const renderErrorMaker = I18n.use(
955
964
  const e2: SupportedErrors | S.ParseResult.ParseError = e
956
965
  return Match.value(e2).pipe(
957
966
  Match.tags({
967
+ NotFoundError: (e) => {
968
+ return intl.formatMessage({ id: "handle.not_found" }, { type: e.type, id: e.id })
969
+ },
958
970
  ParseError: (e) => {
959
971
  console.warn(e.toString())
960
972
  return intl.formatMessage({ id: "validation.failed" })
@@ -1046,7 +1058,17 @@ export const CommanderStatic = {
1046
1058
  ),
1047
1059
  defaultFailureMessageHandler,
1048
1060
  renderError: renderErrorMaker,
1049
- /** Version of withDefaultToast that automatically includes the action name in the default messages and uses intl */
1061
+ /**
1062
+ * Version of withDefaultToast that automatically includes the action name in the default messages and uses intl.
1063
+ * uses the Command id as i18n namespace. `action.{id}` is the main action name,
1064
+ * and `action.{id}.waiting`, `action.{id}.success`, `action.{id}.failure` can be used to override the default messages for the respective states.
1065
+ *
1066
+ * the computed `state` provided to the Command can be used for interpolation in the i18n messages. (the state is captured at the start of each command execution and remains stable throughout)
1067
+ *
1068
+ * Note: if you provide `onWaiting` or `onSuccess` as `null`, no toast will be shown for that state.
1069
+ * If you provide a string or function, it will be used instead of the i18n message.
1070
+ * If you provide an `errorRenderer`, it will be used to render errors in the failure message.
1071
+ */
1050
1072
  withDefaultToast: <A, E, R, Args extends Array<unknown>>(
1051
1073
  options?: {
1052
1074
  errorRenderer?: ErrorRenderer<E, Args>
@@ -1062,19 +1084,37 @@ export const CommanderStatic = {
1062
1084
  const cc = yield* CommandContext
1063
1085
  const { intl } = yield* I18n
1064
1086
  const withToast = yield* WithToast
1087
+ const customWaiting = cc.namespaced("waiting")
1088
+ const hasCustomWaiting = !!intl.messages[customWaiting]
1089
+ const customSuccess = cc.namespaced("success")
1090
+ const hasCustomSuccess = !!intl.messages[customSuccess]
1091
+ const customFailure = cc.namespaced("failure")
1092
+ const hasCustomFailure = !!intl.messages[customFailure]
1065
1093
  return yield* self.pipe(
1066
1094
  (_) =>
1067
1095
  withToast<A, E, Args, R, never, never, I18n>({
1068
- onWaiting: options?.onWaiting === null ? null : intl.formatMessage(
1069
- { id: "handle.waiting" },
1070
- { action: cc.action }
1071
- ),
1096
+ onWaiting: options?.onWaiting === null ? null : hasCustomWaiting
1097
+ ? intl.formatMessage({
1098
+ id: customWaiting
1099
+ }, cc.state)
1100
+ : intl.formatMessage(
1101
+ { id: "handle.waiting" },
1102
+ { action: cc.action }
1103
+ ),
1072
1104
  onSuccess: options?.onSuccess === null
1073
1105
  ? null
1074
1106
  : (a, ..._args) =>
1075
- intl.formatMessage({ id: "handle.success" }, { action: cc.action })
1076
- + (S.is(OperationSuccess)(a) && a.message ? "\n" + a.message : ""),
1077
- onFailure: defaultFailureMessageHandler(cc.action, options?.errorRenderer)
1107
+ hasCustomSuccess
1108
+ ? intl.formatMessage(
1109
+ { id: customSuccess },
1110
+ cc.state
1111
+ )
1112
+ : (intl.formatMessage({ id: "handle.success" }, { action: cc.action })
1113
+ + (S.is(OperationSuccess)(a) && a.message ? "\n" + a.message : "")),
1114
+ onFailure: defaultFailureMessageHandler(
1115
+ hasCustomFailure ? intl.formatMessage({ id: customFailure }, cc.state) : cc.action,
1116
+ options?.errorRenderer
1117
+ )
1078
1118
  })(_, ...args)
1079
1119
  )
1080
1120
  })
@@ -1086,6 +1126,25 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1086
1126
  effect: Effect.gen(function*() {
1087
1127
  const { intl } = yield* I18n
1088
1128
 
1129
+ const makeBaseInfo = <const Id extends string, const I18nKey extends string = Id>(
1130
+ id: Id,
1131
+ options?: Pick<FnOptionsInternal<I18nKey>, "i18nCustomKey">
1132
+ ) => {
1133
+ if (!id) throw new Error("must specify an id")
1134
+ const i18nKey: I18nKey = options?.i18nCustomKey ?? id as unknown as I18nKey
1135
+
1136
+ const namespace = `action.${i18nKey}` as const
1137
+
1138
+ const context = {
1139
+ id,
1140
+ i18nKey,
1141
+ namespace,
1142
+ namespaced: <const K extends string>(k: K) => `${namespace}.${k}` as const
1143
+ }
1144
+
1145
+ return context
1146
+ }
1147
+
1089
1148
  const makeContext = <const Id extends string, const I18nKey extends string = Id>(
1090
1149
  id: Id,
1091
1150
  options?: FnOptionsInternal<I18nKey>
@@ -1100,27 +1159,28 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1100
1159
  id: namespace,
1101
1160
  defaultMessage: id
1102
1161
  }, options?.state)
1103
- const context = {
1162
+ const context = CommandContext.of({
1163
+ ...makeBaseInfo(id, options),
1104
1164
  action,
1105
- id,
1106
- i18nKey,
1107
- namespace,
1108
- namespaced: <const K extends string>(k: K) => `${namespace}.${k}` as const
1109
- }
1165
+ state: options?.state
1166
+ })
1110
1167
 
1111
1168
  return context
1112
1169
  }
1113
1170
 
1114
- const getStateValues = <const I18nKey extends string>(options?: FnOptions<I18nKey, any>) => {
1115
- const state = !options?.state ? undefined : typeof options.state === "function"
1116
- ? computed(options.state)
1117
- : options.state
1171
+ const getStateValues = <const I18nKey extends string, State extends IntlRecord | undefined>(
1172
+ options?: FnOptions<I18nKey, State>
1173
+ ): ComputedRef<State> => {
1174
+ const state_ = options?.state
1175
+ const state = !state_ ? computed(() => undefined as State) : typeof state_ === "function"
1176
+ ? computed(state_)
1177
+ : state_
1118
1178
  return state
1119
1179
  }
1120
1180
 
1121
1181
  const makeCommand = <RT>(runtime: Runtime.Runtime<RT>) => {
1122
1182
  const runFork = Runtime.runFork(runtime)
1123
- return <const Id extends string, const State extends IntlRecord, const I18nKey extends string = Id>(
1183
+ return <const Id extends string, const State extends IntlRecord | undefined, const I18nKey extends string = Id>(
1124
1184
  id_: Id | { id: Id },
1125
1185
  options?: FnOptions<I18nKey, State>,
1126
1186
  errorDef?: Error
@@ -1184,19 +1244,20 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1184
1244
  )
1185
1245
  )
1186
1246
 
1247
+ const currentState = Effect.sync(() => state.value)
1248
+
1187
1249
  const theHandler = flow(
1188
1250
  handler,
1189
1251
  errorReporter,
1190
1252
  // all must be within the Effect.fn to fit within the Span
1191
1253
  Effect.provideServiceEffect(
1192
- CommandContext,
1193
- Effect.sync(() => makeContext_())
1254
+ stateTag,
1255
+ currentState
1194
1256
  ),
1195
1257
  Effect.provideServiceEffect(
1196
- stateTag,
1197
- Effect.sync(() => state?.value)
1198
- ), // todo; service make errors?
1199
- (_) => Effect.annotateCurrentSpan({ action }).pipe(Effect.zipRight(_))
1258
+ CommandContext,
1259
+ Effect.sync(() => makeContext_())
1260
+ )
1200
1261
  )
1201
1262
 
1202
1263
  const [result, exec] = asResult(theHandler)
@@ -1234,11 +1295,22 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1234
1295
  }
1235
1296
  }
1236
1297
 
1237
- const command = Effect.withSpan(
1238
- exec(...args),
1239
- id,
1240
- { captureStackTrace }
1241
- )
1298
+ const command = currentState.pipe(Effect.flatMap((state) =>
1299
+ Effect.withSpan(
1300
+ exec(...args),
1301
+ id,
1302
+ {
1303
+ captureStackTrace,
1304
+ attributes: {
1305
+ input: args,
1306
+ state,
1307
+ action: initialContext.action,
1308
+ id: initialContext.id,
1309
+ i18nKey: initialContext.i18nKey
1310
+ }
1311
+ }
1312
+ )
1313
+ ))
1242
1314
 
1243
1315
  return runFork(command)
1244
1316
  }, { action })
@@ -1491,7 +1563,7 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1491
1563
  ) as any
1492
1564
  )
1493
1565
  },
1494
- makeContext(typeof id === "string" ? id : id.id, { ...options, state: getStateValues(options)?.value }),
1566
+ makeBaseInfo(typeof id === "string" ? id : id.id, options),
1495
1567
  {
1496
1568
  state: Context.GenericTag<`Commander.Command.${Id}.state`, State>(
1497
1569
  `Commander.Command.${typeof id === "string" ? id : id.id}.state`
@@ -1505,7 +1577,7 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1505
1577
  return (_id: any, options?: FnOptions<string, IntlRecord>) => {
1506
1578
  const isObject = typeof _id === "object" || typeof _id === "function"
1507
1579
  const id = isObject ? _id.id : _id
1508
- const context = makeContext(id, { ...options, state: getStateValues(options)?.value })
1580
+ const baseInfo = makeBaseInfo(id, options)
1509
1581
  const idCmd = cmd(id, options)
1510
1582
  // TODO: implement proper tracing stack
1511
1583
  return Object.assign((cb: any) =>
@@ -1519,12 +1591,12 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1519
1591
  },
1520
1592
  ...combinators as [any]
1521
1593
  ),
1522
- context,
1594
+ baseInfo,
1523
1595
  isObject
1524
1596
  ? { mutate: "mutate" in _id ? _id.mutate : typeof _id === "function" ? _id : undefined }
1525
1597
  : {}
1526
1598
  )
1527
- )), context)
1599
+ )), baseInfo)
1528
1600
  }
1529
1601
  }) as unknown as <RT>(
1530
1602
  runtime: Runtime.Runtime<RT>
@@ -1604,7 +1676,7 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1604
1676
  ...combinators as [any]
1605
1677
  ) as any
1606
1678
  )
1607
- }, makeContext(mutation.id, { ...options, state: getStateValues(options)?.value }))
1679
+ }, makeBaseInfo(mutation.id, options))
1608
1680
  }
1609
1681
  }
1610
1682
  })
@@ -9,8 +9,8 @@ export declare const useExperimental: (options?: {
9
9
  messages?: Record<string, string> | Record<string, MessageFormatElement[]>;
10
10
  toasts: any[];
11
11
  }) => {
12
- confirmOrInterrupt: (message?: string | undefined) => Effect.Effect<void, never, import("../src/experimental/intl.js").I18n | import("../src/experimental/confirm.js").Confirm | import("../src/experimental/commander.js").CommandContext>;
13
- confirm: (message?: string | undefined) => Effect.Effect<boolean, never, import("../src/experimental/intl.js").I18n | import("../src/experimental/confirm.js").Confirm | import("../src/experimental/commander.js").CommandContext>;
12
+ confirmOrInterrupt: (message?: string | undefined) => Effect.Effect<void, never, import("../src/experimental/commander.js").CommandContext | import("../src/experimental/intl.js").I18n | import("../src/experimental/confirm.js").Confirm>;
13
+ confirm: (message?: string | undefined) => Effect.Effect<boolean, never, import("../src/experimental/commander.js").CommandContext | import("../src/experimental/intl.js").I18n | import("../src/experimental/confirm.js").Confirm>;
14
14
  updateAction: <Args extends Array<unknown>>(update: (currentActionId: string, ...args: Args) => string) => <A, E, R_1>(_: Effect.Effect<A, E, R_1>, ...input: Args) => Effect.Effect<A, E, import("../src/experimental/commander.js").CommandContext | R_1>;
15
15
  defaultFailureMessageHandler: <E_1, Args extends Array<unknown>, AME, AMR>(actionMaker: string | ((o: import("effect/Option").Option<E_1>, ...args: Args) => string) | ((o: import("effect/Option").Option<E_1>, ...args: Args) => Effect.Effect<string, AME, AMR>), errorRenderer?: (e: E_1, action: string, ...args: Args) => string | undefined) => (o: import("effect/Option").Option<E_1>, ...args: Args) => Effect.Effect<string | {
16
16
  level: "warn";
@@ -21,7 +21,7 @@ export declare const useExperimental: (options?: {
21
21
  errorRenderer?: (e: E_1, action: string, ...args: Args_2) => string | undefined;
22
22
  onWaiting?: null | undefined | string | ((action: string, ...args: Args_2) => string | null | undefined);
23
23
  onSuccess?: null | undefined | string | ((a: A, action: string, ...args: Args_2) => string | null | undefined);
24
- }) => (self: Effect.Effect<A, E_1, R_2>, ...args: Args_2) => Effect.Effect<A, E_1, import("../src/experimental/intl.js").I18n | import("../src/experimental/withToast.js").WithToast | import("../src/experimental/commander.js").CommandContext | R_2>;
24
+ }) => (self: Effect.Effect<A, E_1, R_2>, ...args: Args_2) => Effect.Effect<A, E_1, import("../src/experimental/commander.js").CommandContext | import("../src/experimental/intl.js").I18n | R_2 | import("../src/experimental/withToast.js").WithToast>;
25
25
  alt: <const Id extends string, const I18nKey extends string = Id>(id: Id, customI18nKey?: I18nKey | undefined) => Commander.CommandContextLocal<Id, I18nKey> & (<Args_3 extends Array<unknown>, A, E_2, R_3 extends Toast.Toast | I18n | WithToast | import("../src/experimental/commander.js").CommandContext | `Commander.Command.${Id}.state`>(handler: (...args: Args_3) => Effect.Effect<A, E_2, R_3>) => Commander.CommandOut<Args_3, A, E_2, R_3, Id, I18nKey>);
26
26
  fn: <const Id extends string, const State extends {
27
27
  [x: string]: import("intl-messageformat").PrimitiveType | import("intl-messageformat").FormatXMLElementFn<string, string>;